应用部署到生产环境,启动后,首次登录没问题。再过几分钟或者说再次登录,却出现登录没响应、查询数据界面没响应等
数据库查询没响应的问题,但奇怪的是后台没任何不报错。
初步怀疑是数据库会话数爆满引起的,通过LambdaProbe监控工具,发现应用不响应的时候,存在线程阻塞的情况。
于是 jstack 打印线程快照,如下
"http-80-2" daemon prio=10 tid=0x00007fe67400b000 nid=0x4c04 waiting for monitor entry [0x00007fe669733000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:781)
- waiting to lock <0x00000007a1cbe900> (a org.apache.commons.pool.impl.GenericObjectPool)
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:96)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:880)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:202)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
查了相关DBCP连接池的相关资料,大胆推测是DBCP的BUG问题。
于是将DBCP相关两个依赖包commons-dbcp、commons-pool 为2.X版本,作相关调整后,重新部署应用,线程阻塞问题得以解决。
但却出现了新的问题:首次查询数据库缓慢,等待时间长问题。
问题定位:Apache DBCP连接池获取数据库Connection耗时长
原因是数据库DBA对系统连接资源,进行了限制,空闲连接数据库会进行释放,而系统中默认配置的DBCP连接池,是不对池中的连接做测试的,有时连接已断开了,但DBCP连接池不知道,还以为连接是好的。
解决思路:
- 定时对连接做测试,测试失败就关闭连接。
- 控制连接的空闲时间达到N分钟,就关闭连接,然后连接池可再新建连接。
DBCP设置如下:
testWhileIdle = "true" 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
testOnBorrow = "false" 借出连接时不要测试,否则很影响性能
timeBetweenEvictionRunsMillis = "120000" 每2分钟运行一次空闲连接回收器
minEvictableIdleTimeMillis = "600000" 池中的连接空闲10分钟后被回收,默认值是30分钟。
numTestsPerEvictionRun="3" 每次空闲连接回收器线程(如果有)运行时检查的连接数量,默认值是3.
问题得以解决。
可是奇怪的是集成环境,以及其它采用DBCP 1.X 的应用均没出现线程阻塞或首次查询没响应或响应慢的问题。
在后来的MapReduce导数据到Hbase时,证实是因为应用服务器与数据库服务器间的网络不好引发DBCP相关BUG问题,由于公司部门框架限制,可以的话,还是建议使用其它连接池工具。