WEB应用

解决Tomcat数据连接池无法释放

Jager · 2月27日 · 2014年 · · 9411次已读

近段时间,公司的检测中心报表系统(SMC)的开发人员时不时找到我,说用户老是出现无法登录的情况。前些日子因为手头上有 Jboss 集群的测试工作,发现用户不能登录时,都是在 Tomcat 中将这个项目 Reload 一下就好了,不过只是治标而已,因为大概几个小时之后又会再次出现无法登录的情况。


今天上午,开发人员小毛又找到我,要我协助将这个问题根治一下,拖太久用户难保不投诉。

简单分析了一下,每次 Reload 一下就能解决无法登录的情况,自然而然就想到是不是 session 有问题呢?于是到 Tomcat 的 manager 界面看了下,发现并没有出现 session 粘滞暴涨的情况。

本来可以打开 jconsole 看看的,正好想起了之前用过的 Tomcat 检测工具:probe,于是直接从其他机器上 scp 了一个 probe.war,丢到了 webapps 下面自动部署。

部署完之后,打开了 probe 网页管理后台发现 smc 项目的实时数据库连接数很高,而且只增不减!这个系统的数据池大小设置为 200,此时已经是 100+了,而且一直只升不降。好吧,当数据连接数达到 200 时,问题肯定会再次出现的。

于是我将这个问题告诉了小毛,要他自己去修改连接池释放机制(这里用的是项目单独设定的参数)。他说试过了,没有用,问下我有没有办法。

我这人记性一直欠佳,也很少去记忆一些参数设置,问我么?还我也只能问 BD、GG 了。。。

最终在强大的搜索引擎的帮助下,找到了相关参数说明,通过参考修改后成功解决了问题!

Tomcat 连接池无法释放的解决方法:

编辑项目的连接池配置文件:context.xml,参考下面的【数据库连接设置】参数说明,按照实际情况调整好各项数值,尤其是 Maxidle 和 maxActive。并记得加上 removeAbandoned=true 相关释放参数即可,我们这最终设置好的 context.xml 如下所示:

<Resource name="jdbc/smc"  
          type="javax.sql.DataSource"  
          username="user"  
          password="password"  
          driverClassName="oracle.jdbc.driver.OracleDriver"  
           maxIdle="50"  
           maxWait="2000"  
           removeAbandoned="true"  
           removeAbandonedTimeout="180"  
           validationQuery="select * from dual "  
               url="jdbc:oracle:thin:@192.168.7.98:1521:dw"  
         maxActive="200"/>

数据库连接设置参考:

#数据库连接设置   
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver   
jdbcjdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:DBSERVER   
jdbc.username=user   
jdbc.password=pass   
  
#<!-- 初始化连接 -->  
dataSource.initialSize=10  
  
#<!-- 最大空闲连接 -->  
dataSource.maxIdle=20  
  
#<!-- 最小空闲连接 -->  
dataSource.minIdle=5  
  
#最大连接数量   
dataSource.maxActive=50  
  
#是否在自动回收超时连接的时候打印连接的超时错误   
dataSource.logAbandoned=true  
  
#是否自动回收超时连接   
dataSource.removeAbandoned=true  
  
#超时时间(以秒数为单位)   
dataSource.removeAbandonedTimeout=180  
  
#<!-- 超时等待时间以毫秒为单位 -->  
dataSource.maxWait=1000

附上作者的原文说明:

在配置 DBCP 连接池时,主要难以理解的主要有:removeAbandoned 、logAbandoned、removeAbandonedTimeout、maxWait 这四个参数,设置了 rmoveAbandoned=true 那么在 getNumActive()快要到 getMaxActive()的时候,系统会进行无效的 Connection 的回收,回收的 Connection 为 removeAbandonedTimeout(默认 300 秒)中设置的秒数后没有使用的 Connection,激活回收机制好像是 getNumActive()=getMaxActive()-2。

如果开启"removeAbandoned",那么连接在被认为泄露时可能被池回收. 这个机制在(getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)时被触发.

举例:当 maxActive=20, 活动连接为 18,空闲连接为 1 时可以触发"removeAbandoned".但是活动连接只有在没有被使用的时间超过"removeAbandonedTimeout"时才被删除,默认 300 秒.在 resultset 中游历不被计算为被使用.

logAbandoned=true 的话,将会在回收事件后,在 log 中打印出回收 Connection 的错误信息,包括在哪个地方用了 Connection 却忘记关闭了,在调试的时候很有用。

在这里私人建议 maxWait 的时间不要设得太长,maxWait 如果设置太长那么客户端会等待很久才激发回收事件。

通过仁兄的资料,加深了我对连接池参数的理解,非常感谢!特附上原文地址:DBCP 连接池配置参数说明及优化 ,以示尊重!


问题解决之后,就来玛思阁简单的记录一下,希望能帮到有需要的同行朋友。

12 条回应
  1. 小新 2014-2-27 · 19:25

    我们的技术人员已经完成了修复工作的操作,现在正等待数据库数据传输;成功保证了所有数据完整,大家耐心等待一下,由于数据量比较大,所以没有马上全部恢复,请大家不要着急,没有任何数据丢失

    多说服务已经全部正常,关闭插件的用户现在可以重新打开使用了,对给大家造成的麻烦深表歉意,感谢大家支持

    • avatar
      Jager 2014-2-27 · 19:31

      我是重装才可以重新加载的。

  2. 小新 2014-2-27 · 19:26

    经过此事 多么想把多说本地化啊!!让我这么长时间都无法评论。。

    • avatar
      Jager 2014-2-27 · 19:31

      我说怎么一天没人来我博客留言,回家才发现也不能加载(之前是因为在公司,以为公司网络问题)。下次再抽风,坚决取缔多说,用回原始评论。

      • 小新 2014-2-27 · 20:01

        我是不会css啊,所以制作不出好看的评论框样式,不然早就用本地了。。

        • avatar
          Jager 2014-2-27 · 20:04

          去找些模版改下就是。

  3. 夏日博客 2014-2-28 · 8:36

    昨天来的时候好像不能评论。。。

    • avatar
      Jager 2014-2-28 · 17:06

      昨天多说服务器瘫了。。。都加载不了。

  4. saxo bank cyclisme 2014-2-28 · 16:47

    学习了

    • avatar
      Jager 2014-2-28 · 17:04

      [握手]

  5. 蚂蚁笔记 2014-2-28 · 23:03

    对于技术不懂的我,只能说感谢博主的分享,文章排版很棒,读起来很流畅!

    • avatar
      Jager 2014-3-1 · 7:21

      我这技术型屌丝,文笔不行,写得有点流水账,博友谬赞了。 [呵呵]