一尘不染

在Tomcat中启用Context reload =“ true”时,JDBC连接池用尽了连接

tomcat

我正在Eclipse Juno中开发JavaEEWeb应用程序。我已将Tomcat配置为与PostgreSQL数据库一起使用JDBC连接池(org.apache.tomcat.jdbc.pool)。这是我的项目的META-INF / context.xml中的配置:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <!-- Configuration for the Tomcat JDBC Connection Pool -->
    <Resource name="jdbc/someDB"
        type="javax.sql.DataSource"
        auth="Container"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        driverClassName="org.postgresql.Driver"
        url="jdbc:postgresql://localhost:5432/somedb"
        username="postgres"
        password="12345"
        maxActive="100"
        minIdle="10"
        initialSize="10"
        validationQuery="SELECT 1"
        validationInterval="30000"
        removeAbandoned="true"
        removeAbandonedTimeout="60"
        abandonWhenPercentageFull="50" />
</Context>

我的应用程序是使用Eclipse部署到Tomcat的,并且在Tomcat的context.xml中,可重载属性设置为“
true”,以便在检测到更改时自动重载该Web应用程序:

<Context reloadable="true">

我注意到,每次发生上述自动重装时,都会保留10个到PostgreSQL db的连接(因为在webapp的context.xml initialSize=“10”中)。因此,在进行10次更改后,将引发PSQLException:

org.postgresql.util.PSQLException: FATAL: sorry, too many clients already
...

如果我手动重启Tomcat-一切正常,并且仅保留10个连接。

有谁知道解决此问题的方法,因此可以将reloadable设置为“ true”进行开发,而不会在每次重新加载上下文时导致池化更多的连接吗?

将不胜感激。

PS Apache Tomcat版本7.0.32


阅读 655

收藏
2020-06-16

共1个答案

一尘不染

解决方案(tl; dr)

为了解决此问题,请在context.xml文件中的 Resource 元素中添加一个值为“ close
的属性closeMethod在此处记录)。


这是我的/META-INF/context.xml文件的正确内容:

<Context>
    <!-- Configuration for the Tomcat JDBC Connection Pool -->
    <Resource name="jdbc/someDB"
        type="javax.sql.DataSource"
        auth="Container"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        driverClassName="org.postgresql.Driver"
        url="jdbc:postgresql://localhost:5432/somedb"
        username="postgres"
        password="12345"
        maxActive="100"
        minIdle="10"
        initialSize="10"
        validationQuery="SELECT 1"
        validationInterval="30000"
        removeAbandoned="true"
        removeAbandonedTimeout="60"
        abandonWhenPercentageFull="50"
        closeMethod="close" />
</Context>

注意属性 closeMethod 。我对其进行了测试,现在连接的数量严格按照 context.xml 文件中的定义保持!

注意可能
有一个时刻(与JNDI相关)。有关完整说明,请参见UPDATE 3。


长答案

好的,感谢Apache Tomcat提交者KonstantinKolinko,我找到了上述解决方案。我将此问题报告为ASF
Bugzilla上的Apache Tomcat错误, 事实证明这不是错误 (请参阅UPDATE 1)。

=== 更新1(2012-12-03)又名“新希望” ===

好吧,事实证明那仍然是一个 错误 。Apache Tomcat 7版本管理器Mark Thomas
确认(引用):

“这是jdbc-pool中的内存泄漏错误。PoolCleaner实例保留了对ConnectionPool的引用,从而防止了它被GC损坏
。…
这已在trunk和7.0.x中修复,并将在7.0.34及以后版本中包含。 。”

因此,如果您拥有较旧的Tomcat版本(低于7.0.34),请使用上述解决方案,否则, 从Apache Tomcat
7.0.34版开始,应该不会出现我所描述的问题。
(请参阅更新2)

=== 更新2(2014-01-13)又名“问题反击” ===

即使对于当前最新的Apache Tomcat
7.0.50版,似乎仍然存在我的错误报告中最初描述的问题,并且我还使用Tomcat
7.0.47复制了该问题)。尽管现在Tomcat有时会在重新加载后设法关闭其他连接,有时在一次重新加载后会增加连接数量,然后保持稳定,但是最终这种行为仍然不可靠。

我仍然可以重现
最初描述的问题(尽管同样不那么容易:它可能与连续重新加载的频率有关)。似乎只是时间问题,即,如果Tomcat在重新加载后有足够的时间,它将或多或少地管理连接池。正如马克·托马斯(Mark
Thomas)在他的评论(引号)中所提到的:“根据closeMethod的文档,该方法仅用于加快资源的释放,而这些资源本来可以由GC释放的。”
(报价结尾),速度似乎是决定性因素。

使用Konstantin Kolinko提出的解决方案(使用closeMethod=“close”)时,所有工作都很好,并且保留的连接数严格按照context.xml文件中的定义进行。因此看来,使用closeMethod =“close”是目前唯一避免在重新加载上下文后用尽连接的正确方法。

=== 更新3(2014-01-13)又名“返回Tomcat版本管理器” ===

解决了UPDATE 2中描述的行为背后的谜团。在收到Mark
Thomas(Tomcat版本管理器)的答复后,现在已经清除了更多详细信息。我希望这是最后更新。因此,该错误
的确得到了修复, 如UPDATE 1所述。我在此处将Mark的答复的重要部分作为引号(强调我的)发布:

调查此错误时发现的实际内存泄漏已在7.0.34及更高版本中按注释4至6修复。

连接问题在重新加载时未关闭是JNEE资源的J2EE规范的结果,因此,错误报告的此部分无效。我正在修复此错误的状态,以反映确实存在的内存泄漏已得到修复。

为了进一步说明为什么重新加载后立即关闭连接失败的原因无效,J2EE规范没有为容器提供任何机制来告诉容器不再需要该资源。因此,容器所能做的就是清除对资源的引用并等待垃圾回收(这将触发池​​和关联连接的关闭)。垃圾回收是在JVM确定的时间发生的,因此
这就是在上下文重载后关闭连接花费不确定的时间的原因, 因为一段时间内可能不会发生垃圾回收。

Tomcat已添加了特定于Tomcat的Tomcat JNDI属性closeMethod,该属性可用于在上下文停止时触发JNDI资源的显式关闭。
如果等待GC清理资源是不可接受的,则只需使用此参数 。Tomcat默认情况下不使用此功能,因为
它可能会对某些JNDI资源产生意料之外的副作用

如果您希望看到提供了一种标准机制来告知JNDI资源不再需要它们,那么您需要游说J2EE专家组。

结论

只需使用本文开头提供的解决方案即可(但以防万一,请记住,从 理论上讲 ,使用它可能引起与JNDI相关的问题)。


替代解决方案

MichaelOsipov建议使用他的_CloseableResourceListener_](http://mo-tomcat-ext.sourceforge.net/user-guide.html#CloseableResourceListener)
,它可以防止在取消部署Web应用程序期间由于打开的资源导致的内存泄漏。因此,您也可以尝试一下。


免责声明 UPDATES的别名来自《星球大战》电影系列。所有权利均属于其各自所有者。

2020-06-16