Tomcat线程挂起与DBCP数据库连接池的配置优化

最近网站会出现一个现象是,在并发量大的时候,Tomcat或JBoss的服务线程会线程挂起,同时服务器容易出现数据连接的java.net.SocketException:Broken pipe 的错误。刚才开始咋一看感觉像是DB端处理不来或是DB端的连接时间到了wait_timeout 的时间强行断开。出于这两个目的,网收集了一些资料后,有的说法是在DB的 wait_timeout 时间后断开的一些连接在连接池中处于空闲状态,当应用层获取该连接后进行的DB操作就会发生上面这个错误。
但在我查看了DBCP连接池代码和做了些测试后,发生这种说法并非正确。
1. 首先,出现 Broken pipe 的错误不是因连接超时所致,这个错误只有在Linux下多发,就是在高并发的情况下,网络资源不足的情况出现的, 会发送SIGPIPE信号,LINUX下默认程序退出的,具体解决办法目前还未找到合适的,有的说法是在Linux的环境变量中设置: _JAVA_SR_SIGNUM = 12 基本就可以解决,但经测试结果看并未解决。对于该问题持续关注中。
2. 之后,Broken pipe 问题未彻底解决,那么对于DBCP连接池只好对一些作废的连接要进行强制回收,若这里不做强制回收的话,最终也就会导致 pool exhausted 了,所以这一步一定要加上保护。配置如下:

  1. ####是否在自动回收超时连接的时候打印连接的超时错误
  2. dbcp.logAbandoned=true
  3. ####是否自动回收超时连接
  4. dbcp.removeAbandoned=true
  5. ####超时时间(以秒数为单位)
  6. dbcp.removeAbandonedTimeout=150

3. 对于DB的 wait_timeout 空闲连接时间设置,在超过该时间值的连接,DB端会强行关闭,经测试结果,即使DB强行关闭了空闲连接,对于DBCP而言在获取该连接时无法激活该连接,会自动废弃该连接,重新从池中获取空闲连接或是重新创建连接,从源代码上看,这个自动完成的激活逻辑并不需要配置任何参数,是DBCP的默认操作。故对于网上的不少说连接池时间配置与DB不协调会导致 Broken pipe 的说法是错误,至少对于DBCP是不会出现该问题,也许C3P0是这样。
不过对于连接池的优化而言,本来就在池里空闲的连接被DB给强行关闭也不件好事,这里可以组合以下几个配置解决该问题:

java 代码
  1. #false:空闲时是否验证,若不通过断掉连接,前提是空闲对象回收器开启状态
  2. dbcp.testWhileIdle=true
  3. #-1:以毫秒表示空闲对象回收器由运行间隔。值为负数时表示不运行空闲对象回收器
  4. #若需要回收,该值最好小于minEvictableIdleTimeMillis值
  5. dbcp.timeBetweenEvictionRunsMillis=300000
  6. #1000*60*30:被空闲对象回收器回收前在池中保持空闲状态的最小时间,毫秒表示
  7. #若需要回收,该值最好小于DB中的wait_timeout值
  8. dbcp.minEvictableIdleTimeMillis=320000

4. 最后,还有一个就是DBCP的maxWait参数,该参数值不宜配置太大,因为在池消耗满时,该会挂起线程等待一段时间看看是否能获得连接,一般到池耗尽的可能很少,若真要耗尽了一般也是并发太大,若此时再挂线程的话,也就是同时挂起了Server的线程,若到Server线程也挂满了,不光是访问DB的线程无法访问,就连访问普通页面也无法访问了。结果是更糕。

这样,通过以上几个配置,DBCP连接池的连接泄漏应该不会发生了(当然除了程序上的连接泄漏),不过对于并发大时Linux上的BrokenPipe 问题最好能彻底解决。但是对于并发量大时,Tomcat或JBoss的服务线程会挂起的原因还是未最终定位到原因,目前解决了DBCP的影响后,估计问题可能会是出现在 mod_jk 与 Tomcat 的连接上了,最终原因也有可能是 broken pipe 所致。关注与解决中……

你可能感兴趣的:(tomcat)