dbcp重连问题排查
使用数据库连接池时,免不了会遇到断网、数据库挂掉等异常状况,当网络或数据库恢复时,若无法恢复连接池中的连接,那必然会是一场灾难。
关于dbcp的自动重连配置,网上相关的资料也不少,通过以下资料,并对照官方文档中的参数说明,大致能了解各项配置的含义,我就不冗诉了,本文的目的主要是对问题排查的经过做个简单的记录。
参考资料:
解读dbcp自动重连那些事官方文档
测试环境:
dbcp版本——1.4数据库——postgresSQL 9.10(简称pg)本地(以下称为client)操作系统及数据库服务器(以下称为server)操作系统均为linuxserver位于内网环境,client需要通过vpn或网线直连内网才能访问数据库
首先模拟的是断网的情况
在本地测试dbcp的重连配置时,发现断网后,连接池无法重建连接,分别试过testOnBorrow和testWhileIdle两种validate方式,都没能解决,现象如下:
1. 正常启动应用,在server端通过"select * from pg_stat_activity"查看连接数,会有initialSize个来自client的IDLE连接。——正常
2. 在client端执行各种查询操作,连接数保持不变,且在server端的db log中能看到validate query。——正常
3. 手动切断vpn,client与server断开,查询无法返回结果;然后重连,再次查看连接数,连接数仍保持不变,且连接的创建时间为断网前,即是说连接池认为之前的连接仍然有效,没有销毁旧连接&创建新连接。
4. 此时在应用中执行各种查询操作,均无响应,等待一段时间后(分钟级),超时抛出异常:
Caused by: org.postgresql.util.PSQLException: An I/O error occured while sending to the backend.
Caused by: java.net.SocketException: Connection timed out.
5. 继续通过"select * from pg_stat_activity"查看连接数,隔一段时间后,连接消失。
问题:断网后,仍留在线程池内的连接是否有效?若有效,为什么网络恢复后查询无响应?若无效,为何线程池没有发现并重新创建有效连接?
排查过程:
1.重连vpn后,通过netstat查看client至server的连接
sudo netstat -antop | grep :5432 | grep java
sudo tcpdump -s 65535 -X -i eth0 host xxx.xxx.xxx
<bean id="dataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.user}" /> <property name="password" value="${jdbc.passwd}" /> <property name="removeAbandoned" value="true"/> <property name="initialSize" value="10" /> <property name="maxIdle" value="10" /> <property name="minIdle" value="10" /> <property name="maxActive" value="30" /> <property name="maxWait" value="30000" /> <property name= "testWhileIdle" value="true" /> <property name= "testOnBorrow" value="false" /> <property name= "testOnReturn" value="false" /> <property name= "validationQuery" value="select 1" /> <!-- <property name= "validationQueryTimeout" value="1" /> 配置已失效--> <property name= "timeBetweenEvictionRunsMillis" value="30000" /> <property name= "numTestsPerEvictionRun" value="30" /> <property name="minEvictableIdleTimeMillis" value="1800000" /> </bean>