转载自:http://lc87624.iteye.com/blog/1734089

使用数据库连接池时,免不了会遇到断网、数据库挂掉等异常状况,当网络或数据库恢复时,若无法恢复连接池中的连接,那必然会是一场灾难。 



关于dbcp的自动重连配置,网上相关的资料也不少,通过以下资料,并对照官方文档中的参数说明,大致能了解各项配置的含义,我就不冗诉了,本文的目的主要是对问题排查的经过做个简单的记录。 

参考资料:

测试环境:

  • dbcp版本——1.4
  • 数据库——postgresSQL 9.10(简称pg)
  • 本地(以下称为client)操作系统及数据库服务器(以下称为server)操作系统均为linux
  • server位于内网环境,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的连接

  1. | grep java

注:5432为pg端口,grep java是为了过滤client上的其他形式的连接。 

发现连接数和在server端看到的连接数一致,且均为ESTABLISH状态。 

2. 但在client上执行查询时,通过tcpdump查看client发往server的tcp请求,并无任何请求产生。

  1. -X -i eth0 host xxx.xxx.xxx

可见当前线程池中的连接实际上已经失效了,但dbcp仍认为它是有效的,因此仍在尝试用旧连接访问数据库,直至网络超时。 



于是,开始怀疑是vpn的问题,将client接上网线直连内网后,再次重试上述步骤,只是把断网的方式由切断vpn换成了拔网线,发现这次使用断网前的连接能够正常访问数据库,于是断定是vpn的问题,猜测是重连vpn后,虽然client端ip没有变,但路由的路径已经变了,之前的连接无法复用,但dbcp并不知道。对网络细节不是太熟悉,就不多加揣测了。 



接下来模拟数据库断开client连接的情况 

由于pg采用的是进程模型,与数据库建立的每一个连接都是单独的一个进程,故尝试采用kill进程的方式模拟数据库断开连接。 

预期的结果是:kill掉一个连接进程后,dbcp通过validate query发现该连接失效,将销毁该连接并重新创建新连接。 

但实际情况确是:kill掉一个连接后,所有连接全部被销毁。 

问题:究竟是数据库还是dbcp销毁了所有连接? 

排查过程: 

熟悉pg的同事认为pg之所以采用进程模型,就是为了避免连接之间的影响,因此不可能发生kill一个连接,其他连接也被销毁的情况。在这个理论前提下,问题就变得很诡异,因为dbcp的validate肯定是针对一个连接的,也不可能会在validate一个连接失效的情况下销毁所有连接,于是越想越偏,甚至开始怀疑是pg的jdbc
driver有问题,最终放弃了深究。 

但我总觉得有点不太对劲,于是推翻之前的前提,开始怀疑是pg销毁了所有连接。于是,在使用连接池的应用之外,通过pg的数据库客户端psql连接db,这就建立了一个与dbcp无关的连接,接着继续在server端kill了一个连接池中的连接,继而发现psql创建的连接也被销毁了,这就能确定是pg在销毁连接,因为dbcp不可能控制自身范围之外的连接。 

后来才知道,pg之所以会这么做,是因为我们kill连接时使用的是kill -9(简称9杀),9杀太过粗暴,pg会重启很多内部进程,以保证所有进程正常,之前的连接也将会丢失,换用普通的kill命令,则不会发生以上情况。可见9杀很多情况下是十分危险的,试想一个线上db,若是9杀一个连接,后果不堪设想。。。 



总结 

说是dbcp问题排查,但大家可以看到最终问题的根源都跟dbcp没有什么关系。实际工作中的很多问题,关联的因素众多,需要有各方面的知识储备才能找到真正问题根源,否则就会把问题归结到一个自己不太了解的领域。 

另外,看到dbcp基本配置和重连配置这篇文章中对连接池重连有两句不错的总结,引用一下:

引用
1. 数据库意外重启后,原先的数据库连接池能自动废弃老的无用的链接,建立新的数据库链接 

2. 网络异常中断后,原先的建立的tcp链接,应该能进行自动切换

最后附上测试使用的dbcp配置。 

testOnBorrow配置:

  1. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  2. <property name="driverClassName" value="${jdbc.driver}" />
  3. <property name="url" value="${jdbc.url}"/>
  4. <property name="username" value="${jdbc.user}" />
  5. <property name="password" value="${jdbc.passwd}" />
  6. <property name="removeAbandoned" value="true"/>
  7. <property name="initialSize" value="10" />
  8. <property name="maxIdle" value="10" />
  9. <property name="minIdle" value="10" />
  10. <property name="maxActive" value="30" />
  11. <property name="maxWait" value="30000" />
  12. <property name= "testWhileIdle" value="false" />
  13. <property name= "testOnBorrow" value="true" />
  14. <property name= "testOnReturn" value="false" />
  15. <property name= "validationQuery" value="select 1" />
  16. <!-- <property name= "validationQueryTimeout" value="1" /> 配置已失效-->
  17. </bean>

testWhileIdle配置:

  1. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  2. <property name="driverClassName" value="${jdbc.driver}" />
  3. <property name="url" value="${jdbc.url}"/>
  4. <property name="username" value="${jdbc.user}" />
  5. <property name="password" value="${jdbc.passwd}" />
  6. <property name="removeAbandoned" value="true"/>
  7. <property name="initialSize" value="10" />
  8. <property name="maxIdle" value="10" />
  9. <property name="minIdle" value="10" />
  10. <property name="maxActive" value="30" />
  11. <property name="maxWait" value="30000" />
  12. <property name= "testWhileIdle" value="true" />
  13. <property name= "testOnBorrow" value="false" />
  14. <property name= "testOnReturn" value="false" />
  15. <property name= "validationQuery" value="select 1" />
  16. <!-- <property name= "validationQueryTimeout" value="1" /> 配置已失效-->
  17. <property name= "timeBetweenEvictionRunsMillis" value="30000" />
  18. <property name= "numTestsPerEvictionRun" value="30" />
  19. <property name="minEvictableIdleTimeMillis" value="1800000" />
  20. </bean>

注:testOnBorrow只会发现当前连接失效,再创建一个连接供当前查询使用,而testWhileIdle会定时校验numTestsPerEvictionRun个连接,只要发现连接失效,就将其移除再重新创建。

dbcp重连问题排查的更多相关文章

  1. DBCP重连的问题及解决办法(转)

    本文转载:http://lc87624.iteye.com/blog/1734089,欢迎大家阅读原文. 使用数据库连接池时,免不了会遇到断网.数据库挂掉等异常状况,当网络或数据库恢复时,若无法恢复连 ...

  2. zookeeper 大量连接断开重连原因排查

    转自:http://blog.csdn.net/hengyunabc/article/details/41450003?utm_source=tuicool&utm_medium=referr ...

  3. spring + mybatis配置及网络异常设置

    Spring引入mybatis <beans xmlns="http://www.springframework.org/schema/beans" xmlns:contex ...

  4. spring boot + dubbo开发遇到过的异常

    异常信息 NoClassDefFoundErrororg.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1162) Sessio ...

  5. Hbase记录-client访问zookeeper大量断开以及参数调优分析(转载)

    1.hbase client配置参数 超时时间.重试次数.重试时间间隔的配置也比较重要,因为默认的配置的值都较大,如果出现hbase集群或者RegionServer以及ZK关掉,则对应用程序是灾难性的 ...

  6. dbcp基本配置和重连配置 -- mysql 8小时自动断开连接的问题

    1. 引入dbcp (选择1.4) Java代码   com.alibaba.external jakarta.commons.dbcp 1.4 2. dbcp的基本配置 相关配置说明: initia ...

  7. 解读dbcp自动重连那些事---转载

    http://agapple.iteye.com/blog/791943 可以后另一篇做对比:http://agapple.iteye.com/blog/772507 同样的内容,不同的描述方式,不一 ...

  8. 【DBCP】DBCP基本配置和重连配置+spring中配置

    最近在看一些dbcp的相关内容,顺便做一下记录,免得自己给忘记了.   1. 引入dbcp (选择1.4) <dependency> <groupId>com.alibaba. ...

  9. 解读dbcp自动重连那些事(转)

    本文转自:http://agapple.iteye.com/blog/791943 可以后另一篇做对比:http://agapple.iteye.com/blog/772507 borrow 借,从连 ...

随机推荐

  1. linux安装软件的几种方式(kali平台)和一些实用的软件(持续更新)

    安装软件前我们先更改镜像源,编辑 /etc/apt/sources.list 文件, 在文件最前面添加以下条目: #中科大更新源 deb https://mirrors.ustc.edu.cn/kal ...

  2. 从C到C++ (2)

    从C到C++ (2) 一.    C++中增加了作用域标示符 :: 1.     用于对局部变量同名的全局变量进行访问. 2.     用于表示类成员. 二.    new.delete运算符 1.  ...

  3. THUSC 2018 游记

    现在是闭幕式,我坐在西郊宾馆后排,开始写这篇游记. day0 早上从临汾坐火车到北京,12:52左右到了北京. 这次北京的地铁安检没有排成很长的队,但是在买票的时候我惊喜地发现我身上没有零钱--所幸北 ...

  4. 如何搭建SBT编译Scala开发的Android工程

    作者:戚明峰 最近接触了shadowsocks的Android客户端项目源码(https://github.com/shadowsocks/shadowsocks-android),刚好这个项目是使用 ...

  5. 预装win8的笔记本如何重装win7

    测试电脑联想T440. 开机按F1,然后Enter,进入Bios设置. 先关闭Secure Boot,然后设置为Legacy Boot. 之后才能设置U盘为第一启动盘. 进入老毛桃的PE系统,使用Di ...

  6. Android Open Source Projects(汇总与整理)

    Android Open Source Projects 目前包括: Android开源项目第一篇——个性化控件(View)篇  包括ListView.ActionBar.Menu.ViewPager ...

  7. Spark搭档Elasticsearch

    Spark与elasticsearch结合使用是一种常用的场景,小编在这里整理了一些Spark与ES结合使用的方法.一. write data to elasticsearch利用elasticsea ...

  8. VC++之运算符重载简单小结

    封装继承和多态是面向对象三大基本支柱.在面向对象系统中有两种编译方式:静态联编和动态联编静态联编:也叫早期联编:指系统在编译时就决定如何实现某一动作,提供了执行速度快的优点.动态联编:也叫滞后联编:指 ...

  9. springmvc文件上传,出现400 的错误问题

    遇见的原因是公司系统上的图片上传忽然不好使了,报错400.单独针对这个模块调了好长时间都没解决,后来才发现前几天做过一个excel上传导入的功能... 使用SptingMVC3.1.3 对于文件上传提 ...

  10. window下对samba的清理操作

    windows清除访问samba局域网密码缓存 1.在dos窗口中输入control userpasswords2或者control keymgr.dll,然后[高级]/[密码管理],删掉保存的该机器 ...