Java H2-Tomcat jdbc连接池在达到最大限制时不回收连接

Java H2-Tomcat jdbc连接池在达到最大限制时不回收连接,java,tomcat,h2,jdbc-pool,Java,Tomcat,H2,Jdbc Pool,问题陈述 我们在嵌入式模式下使用H2已有一段时间了。它上面配置了一个连接池。以下是当前池配置: h2.datasource.min-idle=10 h2.datasource.initial-size=10 h2.datasource.max-active=200 h2.datasource.max-age=600000 h2.datasource.max-wait=3000 h2.datasource.min-evictable-idle-time-millis=60000 h2.dataso

问题陈述

我们在嵌入式模式下使用H2已有一段时间了。它上面配置了一个连接池。以下是当前池配置:

h2.datasource.min-idle=10
h2.datasource.initial-size=10
h2.datasource.max-active=200
h2.datasource.max-age=600000
h2.datasource.max-wait=3000
h2.datasource.min-evictable-idle-time-millis=60000
h2.datasource.remove-abandoned=true
h2.datasource.remove-abandoned-timeout=60
h2.datasource.log-abandoned=true
h2.datasource.abandonWhenPercentageFull=100
H2配置:

spring.h2.console.enabled=true
spring.h2.console.path=/h2
h2.datasource.url=jdbc:h2:file:~/h2/cartdb
h2.server.properties=webAllowOthers
spring.h2.console.settings.web-allow-others=true
h2.datasource.driver-class-name=org.h2.Driver
*跳过用户名和密码属性

我们已经通过记录池属性验证了上述配置的有效性

这个设置的问题是,我们观察到连接池经常(尽管是间歇性的)耗尽,一旦连接池达到最大限制,它就开始为一些查询抛出以下异常

LogExceptionHelper(SqlExceptionHelper.java:129)-[http-apr-8080-exec-38]超时:池为空。无法在3秒钟内获取连接,无可用连接[大小:200;忙:200;空闲:0;上次等待:3000]

此后,即使在我们重新启动web服务器(本例中为tomcat)之前的许多小时,它也无法从这种状态恢复

H2驱动程序依赖关系:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.196</version>
    <scope>runtime</scope>
</dependency>

com.h2数据库
氢
1.4.196
运行时
查询模式和吞吐量

我们使用h2为每个请求加载一些数据,然后执行一些(大约50个)SELECT查询,最后删除数据。这导致在h2(根据new relic monitoring)上每分钟有30k-40k个呼叫(非工作时间除外)

每个读取操作都会获取一个新连接,并在执行后释放该连接

EntityManager entityManager = null;
try {
     entityManager = entityManagerFactory.createEntityManager();
     Query query = entityManager.createNativeQuery(sqlQuery);
     query.setParameter("cartId", cartId);
     List<String> resultList = query.getResultList();
     return resultList;
} finally {
         if(null != entityManager) { entityManager.close(); }
}
EntityManager EntityManager=null;
试一试{
entityManager=entityManagerFactory.createEntityManager();
Query Query=entityManager.createNativeQuery(sqlQuery);
query.setParameter(“cartId”,cartId);
List resultList=query.getResultList();
返回结果列表;
}最后{
如果(null!=entityManager){entityManager.close();}
}
观察结果

  • 应用程序重新启动后,池利用率将降至最低,直到池利用率突然上升并最终达到最大限制。这种情况持续1-2天
  • 一旦池达到最大连接限制,与返回的连接计数相比,借用的连接计数将以更快的速度增加,否则返回的连接计数将彼此非常接近
  • 同时,放弃的连接计数也开始随着放弃日志的增加而增加
  • 有趣的是,池耗尽后,查询响应时间保持不变。这样就排除了慢速查询
  • 这个问题甚至发生在交通量最小的最奇怪的时刻。因此,它与交通无关
请引导我们朝着正确的方向解决这个问题

更新

最近,当发生这样的事件时,我们在堆栈跟踪中发现了以下原因:

原因:org.h2.jdbc.JdbcSQLException:数据库可能已处于 用法:null。可能的解决方案:关闭所有其他连接;使用 服务器模式[90020-196]

原因:java.lang.IllegalStateException:文件已锁定: nio:/root/h2/cartdb.mv.db[1.4.196/7]

原因:java.nio.channels.OverlappingFileLockException

因此,在深入研究这一点之后,我们决定转向内存模式,因为我们不需要在应用程序的生命周期之外保存数据。因此,不应发生文件锁定,从而减少或消除此问题


将返回并在任何情况下更新。

自上次更新问题后:

在观察了相当长一段时间的性能之后,我们得出结论,在文件模式(嵌入式)中使用H2不知何故会定期导致文件锁定异常(尽管不规则)

由于我们的应用程序不需要在应用程序的生命周期之后保存数据,因此我们决定转向纯内存模式


尽管文件锁异常的神秘性还需要揭示。

您使用的是哪个H2 jdbc驱动程序版本;这是最新的吗?我们使用的是1.4.196。1.4.197是截至2018年3月的最新版本。@MickMnemonic,我似乎找不到最新版本的发行说明,所以不知道版本升级是否能解决问题。@manu列出了1.4.196的250个错误修复!因此,如果升级对您来说是可行的,那么升级似乎是值得的,即使它不一定能解决您的特定问题。感谢@skomisa提供的发行说明。我在看他们的Github回购协议。我肯定能做到。