`
lc87624
  • 浏览: 144159 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

dbcp重连问题排查

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

关于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的连接
sudo netstat -antop | grep :5432  | grep java

注:5432为pg端口,grep java是为了过滤client上的其他形式的连接。
发现连接数和在server端看到的连接数一致,且均为ESTABLISH状态。
2. 但在client上执行查询时,通过tcpdump查看client发往server的tcp请求,并无任何请求产生。
sudo tcpdump -s 65535 -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配置:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 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="false" />
        <property name= "testOnBorrow" value="true" />
        <property name= "testOnReturn" value="false" />
        <property name= "validationQuery" value="select 1" />
        <!-- <property name= "validationQueryTimeout" value="1" /> 配置已失效-->
    </bean>



testWhileIdle配置:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 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>


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

相关推荐

    commons-dbcp-1.3

    `commons-dbcp-1.3-src.zip`包含了DBCP 1.3的源代码,开发者可以深入理解其内部机制,进行定制化开发或者排查问题。 7. **依赖与集成**: DBCP通常与其他Java数据库访问组件一起使用,如JDBC驱动。在Maven项目中...

    使用DBCP链接池详解附加代码例子

    - `logAbandoned`:是否记录废弃连接的信息,有助于排查问题。 通过调整这些参数,可以灵活地管理和优化连接池的行为,适应不同的应用需求和负载情况。 总结起来,DBCP连接池通过高效的连接管理和复用机制,显著...

    dbcp数据连接池配置

    2. **logAbandoned**: 如果设置为`true`,DBCP会在回收废弃连接时记录日志,包含错误信息和哪个代码位置未正确关闭连接,这对于调试和排查问题非常有用。 3. **removeAbandonedTimeout**: 这个参数定义了连接被标记...

    commons-dbcp-1.2.2-src.zip

    源代码对于开发者来说是宝贵的资源,因为它允许深入理解组件的工作原理,进行定制化修改,以及排查可能出现的问题。 描述中提到的"在开发时常会用到的,一个包,有的tomcat中会自带,但有时却没有",揭示了DBCP在...

    自己封装的dbcp连接池封装,可以同时连接多个数据库

    8. **监控与日志**:为了方便问题排查和性能优化,连接池通常会提供监控接口和日志功能,记录连接的创建、使用、回收等信息。 9. **代码完善**:您提到这个封装做得不是很严谨,可能需要其他开发者进一步完善。这...

    dbcp jar包

    4. **监控和调整**: 在运行时,可以通过监控工具检查DBCP的运行状态,如当前连接数、活动连接数等,以便于调优和问题排查。 5. **关闭**: 应用结束时,记得关闭数据源,释放所有资源,避免内存泄漏。 除了DBCP,...

    用apache的dbcp来建立数据库连接池

    - 监控和日志:监控连接池的状态,记录异常日志,有助于问题排查和性能优化。 总的来说,Apache DBCP提供了一个简单易用且功能强大的数据库连接池解决方案,通过合理配置和使用,可以有效地提升Java应用处理数据库...

    day18 16.dbcp连接池使用介绍

    标题中的“day18 16.dbcp连接池使用介绍”指的是一个关于数据库连接池(DBCP)的教程,可能是第18天课程的第16个部分。...同时,深入理解DBCP的源码也有助于开发者在遇到问题时能够更有效地排查和解决。

    dbcp 连接池不合理的锁导致连接耗尽解决方案

    5. **监控和报警**:设置合适的监控指标,如连接池中的连接数量、等待连接的线程数等,一旦发现问题能及时报警并进行排查。 通过上述调整和优化,可以有效地解决DBCP连接池不合理的锁导致的连接耗尽问题,提高系统...

    配置log4j配置数据库连接池(以dbcp连接池为例),并将log信息存储在数据库中(以mysql为例)

    在IT行业中,日志管理是系统监控和故障排查的关键环节。Log4j是Apache提供的一款强大的日志处理框架,广泛应用于Java应用中。它允许开发者灵活地控制日志信息的输出,包括输出级别、格式、目标等。而数据库连接池如...

    Java连接MySQL数据库失败的一种可能原因

    总之,Java连接MySQL数据库失败的原因多样,解决这个问题需要细致的排查和适当的优化策略。通过理解JDBC的工作原理、检查连接参数、确保驱动兼容性、管理好数据库连接池,我们可以有效地避免和解决此类问题。

    编写一个基本的连接池来实现连接的复用

    5. **连接池的监控**:提供监控功能,统计连接的使用情况,如当前连接数、活跃连接数、等待队列长度等,以便于性能优化和问题排查。 6. **异常处理**:当出现错误时,连接池需要能够优雅地处理,如捕获并记录异常,...

    连接不到数据库【转】归纳.pdf

    在排查问题时,应按照由简单到复杂的原则进行,如先检查基础配置,再考虑更深层次的技术问题。同时,记录并分析错误日志,可以帮助更快地定位问题所在。一旦解决了上述问题,数据库连接通常就能恢复正常。如果问题...

    连接不到数据库【转】整理.pdf

    4. **配置文件错误**:在某些情况下,问题可能源于数据库连接池的配置,例如使用Apache Commons DBCP。错误的配置可能导致`PoolableConnectionFactory`无法创建,从而抛出`SQLNestedException`。检查`server.xml`...

    tomcat中连接oracle数据库的问题[归纳].pdf

    【Tomcat与Oracle数据库连接详解】 Tomcat,作为Apache Jakarta项目的子项目,是Sun公司推荐的JSP和Servlet容器,以其高效...在遇到连接问题时,应从这些方面进行排查,以确保应用程序能够顺利地与数据库进行通信。

    JAVA源代码连接池

    - 监控与日志:连接池提供监控接口,可以通过监控工具收集性能指标,帮助优化配置和排查问题。 通过理解这些连接池的工作原理和配置,开发者可以更好地管理和优化数据库连接,提高应用程序的性能和稳定性。在Java...

    jave连接sql2005全

    三、连接问题排查 在尝试连接 SQL Server 2005 时,可能遇到的问题包括但不限于网络问题、权限问题、驱动未正确加载等。以下是检查和解决这些问题的步骤: 1. **网络测试**: 使用 Telnet 命令测试 SQL Server ...

    自定义JDBC连接池及常用连接池介绍

    在IT行业中,数据库连接管理是应用系统性能优化的关键一环,而JDBC连接池就是解决这一问题的有效工具。...在实际开发中,可以结合源码阅读,深入了解其内部机制,以便更好地进行定制化配置和问题排查。

    早期写的数据库连接池

    - 监控和日志:记录连接池的使用情况,如连接创建、释放、异常等,以便于问题排查和性能调优。 总之,早期的数据库连接池设计为我们提供了高效、可靠的数据库连接管理手段,随着技术的发展,现代的连接池如HikariCP...

Global site tag (gtag.js) - Google Analytics