eclipse 在 Tomcat 中启用 Context reload="true" 时,JDBC 连接池耗尽了连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13595794/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JDBC connection pool runs out of connections when Context reload="true" is enabled in Tomcat
提问by informatik01
I am developing a Java EE web application in Eclipse Juno. I have configured Tomcat to use JDBC connection pool (org.apache.tomcat.jdbc.pool) along with PostgreSQL database. Here are the configurations in my project's META-INF/context.xml:
我正在 Eclipse Juno 中开发 Java EE Web 应用程序。我已将 Tomcat 配置为使用 JDBC 连接池 (org.apache.tomcat.jdbc.pool) 和 PostgreSQL 数据库。以下是我项目的 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>
My application is deployed to Tomcat using Eclipse, and in Tomcat's context.xml an attribute reloadable is set to "true" to automatically reload the web application if a change is detected:
我的应用程序使用 Eclipse 部署到 Tomcat,并且在 Tomcat 的 context.xml 中,一个属性 reloadable 设置为“true”以在检测到更改时自动重新加载 Web 应用程序:
<Context reloadable="true">
<Context reloadable="true">
I have noticed that every time the above mentioned automatic reload is happening 10 more connections to PostgreSQL db is reserved (because in webapp's context.xml initialSize="10"). So after 10 changes a PSQLException is thrown:
我注意到每次发生上述自动重新加载时,都会保留 10 个与 PostgreSQL 数据库的连接(因为在 webapp 的 context.xml initialSize="10" 中)。因此,在 10 次更改后会抛出 PSQLException:
org.postgresql.util.PSQLException: FATAL: sorry, too many clients already
...
If I manually restart Tomcat - everything is fine and just 10 connections are reserved.
如果我手动重新启动 Tomcat - 一切都很好,只保留了 10 个连接。
Does anybody know the way around this issue, so it could be possible to develop with reloadable set to "true" and not cause pooling more connections every time the context is reloaded?
有没有人知道解决这个问题的方法,所以有可能在 reloadable 设置为“true”的情况下进行开发,并且每次重新加载上下文时都不会导致池更多的连接?
Would appreciate any help.
将不胜感激任何帮助。
P.S. Apache Tomcat Version 7.0.32
PS Apache Tomcat 版本 7.0.32
回答by informatik01
THE SOLUTION (tl;dr)
解决方案(tl;博士)
In order to solve this issue, add an attribute closeMethod
(documented here) with the value "close" to the Resourceelement in the context.xml file.
为了解决此问题,请向 context.xml 文件中的Resource元素添加一个值为“ close”的属性closeMethod
(在此处记录)。
Here's the correct content of my /META-INF/context.xml file:
这是我的 /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>
Pay attention to the attribute closeMethod. I tested it and now the number of connections are kept STRICTLY as defined in the context.xmlfile!
注意属性closeMethod。我对其进行了测试,现在连接数严格按照context.xml文件中的定义保持不变!
NOTE
There is one moment (related to JNDI) that may be taken care of. See the UPDATE 3 for the complete description.
注意
有一个时刻(与 JNDI 相关)可以处理。有关完整说明,请参阅更新 3。
Long answer
长答案
OK, I found the above solution thanks to Apache Tomcat committor Konstantin Kolinko. I reported this issueas an Apache Tomcat bug on ASF Bugzilla and it turned out it's not a bug(see UPDATE 1).
好的,感谢 Apache Tomcat 提交者Konstantin Kolinko,我找到了上述解决方案。我在 ASF Bugzilla 上将此问题报告为 Apache Tomcat 错误,结果证明它不是错误(请参阅更新 1)。
=== UPDATE 1 (2012-12-03) aka "A New Hope"===
===更新 1 (2012-12-03) 又名“新希望”===
Well, it still turned out to be a bug. Mark Thomas, the Apache Tomcat 7 release manager, confirmedthat (quote):
嗯,结果仍然是一个错误。Apache Tomcat 7 发布经理Mark Thomas确认(引用):
"This is a memory leak bug in jdbc-pool. PoolCleaner instances are retaining references to the ConnectionPool preventing it from being GC'd.
...
This has been fixed in trunk and 7.0.x and will be included in 7.0.34 onwards."
“这是 jdbc-pool 中的内存泄漏错误。PoolCleaner 实例保留对 ConnectionPool 的引用,防止它被 GC 处理
。......
这已在主干和 7.0.x 中修复,并将包含在 7.0.34 之后.”
So if you have an older Tomcat version (less than 7.0.34), use the above solution, otherwise, starting with Apache Tomcat version 7.0.34, there should be no issues like the one I described.(see UPDATE 2)
所以如果你有一个较旧的Tomcat版本(小于7.0.34),使用上面的解决方案,否则,从Apache Tomcat 7.0.34版本开始,应该没有我描述的问题。(见更新 2)
=== UPDATE 2 (2014-01-13) aka "The Issue Strikes Back"===
===更新 2 (2014-01-13) 又名“问题反击”===
It seems like the issue initially described in my bug reportis still present even for the currently latest Apache Tomcat version 7.0.50 and I also reproduced it with Tomcat 7.0.47 (thanks to Miklos Krivanfor pointing it out). Although now Tomcat sometimes manages to close additional connections after reloading, and sometimes the number of connections are increased after one reload and then kept steady, but eventually this behavior is still not reliable.
即使对于当前最新的 Apache Tomcat 7.0.50 版,我的错误报告中最初描述的问题似乎仍然存在,并且我还使用 Tomcat 7.0.47 重现了它(感谢Miklos Krivan指出它)。虽然现在Tomcat有时会在重新加载后设法关闭额外的连接,有时在重新加载后连接数增加然后保持稳定,但最终这种行为仍然不可靠。
I still could reproducethe initially described issue (although again not that easy: it may be related to the frequency of successive reloads). Seems like it's just a matter of time, i.e. if Tomcat has enough time after reload, it manages the connection pool more or less as it should. As Mark Thomas mentioned in his comment(quote): "As per the docs for closeMethod, that method exists solely to speed up the freeing of resources that would otherwise be freed by GC." (end of quote), and it looks like the speed is the defining factor.
我仍然可以重现最初描述的问题(虽然也不是那么容易:它可能与连续重新加载的频率有关)。似乎这只是时间问题,即如果 Tomcat 在重新加载后有足够的时间,它会或多或少地管理连接池。正如马克托马斯在他的评论(引用)中提到的那样:“根据 closeMethod 的文档,该方法的存在只是为了加速释放资源,否则这些资源将被 GC 释放。” (引用结束),看起来速度是决定性因素。
When using the solution presented by Konstantin Kolinko (to use closeMethod="close") everything WORKS just fine, and the number of connections reserved are kept STRICTLY as defined in the context.xml file. So it appears that using closeMethod="close" is the ONLY true way (at the moment) to avoid running out of connections after context reloading.
当使用 Konstantin Kolinko 提供的解决方案(使用 closeMethod="close")时,一切正常,并且保留的连接数严格按照 context.xml 文件中的定义进行保留。因此,使用 closeMethod="close" 似乎是(目前)避免在上下文重新加载后耗尽连接的唯一正确方法。
=== UPDATE 3 (2014-01-13) aka "Return of the Tomcat Release Manager"===
===更新 3 (2014-01-13) 又名“Tomcat Release Manager 的回归”===
The mystery behind the behavior described in the UPDATE 2 is solved. More details have been cleared now after I received a replyfrom Mark Thomas (Tomcat release manager). I hope this is the last update. So the bug was indeed fixedas was mentioned in the UPDATE 1. I am posting the essential part from Mark's reply here as a quote (emphasis mine):
解决了 UPDATE 2 中描述的行为背后的奥秘。在我收到Mark Thomas(Tomcat 发布经理)的回复后,现在已经清除了更多细节。我希望这是最后一次更新。因此,正如更新 1 中提到的那样,该错误确实已修复。我将 Mark 回复中的重要部分作为引用发布(强调我的):
The actual memory leak found while investigating this bug has been fixed in 7.0.34 onwards as per comments #4 to #6.
The issue of the connections not being closed on reload is a result of the J2EE specification for JNDI resources and this part of the bug report is therefore invalid. I am restoring the state of this bug to fixed to reflect that the memory leak that did exist has been fixed.
To expand on why the failure to immediately close connection after reload is invalid, the J2EE specification provides no mechanism for the container to tell the resource it is no longer required. Therefore all the container can do is clear references to the resource and wait for garbage collection (which will trigger the closure of the pool and the associated connections). Garbage collection occurs at times determined by the JVM so this is why it takes an indeterminate amount of time for connections to be closed after a context reloadas a garbage collection may not occur for some time.
Tomcat has added the Tomcat specific JNDI attribute closeMethod which can be used to trigger the explicit close of a JNDI resource when a context is stopped. If waiting for GC to clean up resources is not acceptable then simply use this parameter. Tomcat does not use this by default as it may have unexpected and unwanted side-effects for some JNDI resources.
If you'd like to see a standard mechanism provided for telling JNDI resources that they are no longer required then you need to lobby the J2EE expert group.
在调查此错误时发现的实际内存泄漏已在 7.0.34 以后根据评论 #4 到 #6 修复。
重新加载时连接未关闭的问题是 JNDI 资源的 J2EE 规范的结果,因此这部分错误报告无效。我正在将此错误的状态恢复为已修复,以反映确实存在的内存泄漏已得到修复。
为了详细说明重新加载后立即关闭连接失败的原因是无效的,J2EE 规范没有提供让容器告诉资源它不再需要的机制。因此,容器所能做的就是清除对资源的引用并等待垃圾收集(这将触发池和相关连接的关闭)。垃圾收集发生的时间由 JVM 确定,因此这就是为什么在上下文重新加载后关闭连接需要不确定的时间,因为垃圾收集可能在一段时间内不会发生。
Tomcat 添加了特定于 Tomcat 的 JNDI 属性 closeMethod,该属性可用于在上下文停止时触发 JNDI 资源的显式关闭。如果等待 GC 清理资源是不可接受的,那么只需使用此参数。Tomcat 默认不使用它,因为它可能会对某些 JNDI 资源产生意外和不需要的副作用。
如果您希望看到提供的标准机制来告知 JNDI 资源不再需要它们,那么您需要游说 J2EE 专家组。
Conclusion
结论
Just use the solution presented in the beginning of this post (but, just in case, keep in mind the JNDI related issue that can theoreticallyarise from using it).
只需使用本文开头介绍的解决方案(但为了以防万一,请记住理论上使用它可能会引起的 JNDI 相关问题)。
Alternative solution
替代方案
Michael Osipovsuggested using his CloseableResourceListener, which prevents memory leaks caused by left open resources during undeployment of web applications. So you may also give it a try.
Michael Osipov建议使用他的CloseableResourceListener,它可以防止在取消部署 Web 应用程序期间由于留下打开的资源而导致的内存泄漏。所以你也可以试一试。
DISCLAIMER
The aliases for the UPDATES were inspired by the Star Warsfilm series. All rights belong to their respective owners.
免责声明
UPDATES 的别名的灵感来自星球大战电影系列。所有权利均属于其各自所有者。