H2 - Tomcat jdbc连接池一旦达到最大限制

时间:2018-05-04 20:42:35

标签: 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.datasource.remove-abandoned=true
h2.datasource.remove-abandoned-timeout=60
h2.datasource.log-abandoned=true
h2.datasource.abandonWhenPercentageFull=100

H2 config:

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

*跳过用户名和密码属性。

我们已通过记录池属性验证上述配置生效。

此设置的问题是我们正在观察常规(但间歇性)连接池耗尽,一旦池达到最大限制,它就会开始为某些查询抛出以下异常。

  

SqlExceptionHelper.logExceptions(SqlExceptionHelper.java:129) - [http-apr-8080-exec-38]超时:池为空。无法在3秒内获取连接,无法使用[size:200;忙:200;空闲:0; lastwait:3000]

此后,即使在我们重启Web服务器(在本例中为tomcat)之后的几个小时内它也无法从此状态恢复。

H2驱动程序依赖:

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

查询模式&amp;可以通过

我们使用h2为每个请求加载一些数据,然后执行一些(大约50个)SELECT查询,最后删除数据。这导致在h2上每分钟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(); }
}

观察

  • 应用程序重启后,池利用率最低,直到池利用率突然上升并最终达到最大限制。这种情况在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

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

在任何一种情况下都会回来更新。

1 个答案:

答案 0 :(得分:0)

自上次更新问题以来:

在观察了性能很长一段时间之后,我们得出的结论是,在文件模式(嵌入式)中使用H2会以某种方式定期导致文件锁定异常(尽管不规则)。

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

虽然文件锁定例外的谜团仍需要披露。

相关问题