记一次druid线程池溢出的分析解决过程--来源于生产实践

背景:

1、2019年春节前后,在将近一个月的时间内,生产服务集群中的两个节点先后发生连接池(druid实现)溢出现象,无法获取连接进行DB操作。

2、通过Jconsole连接到生产JVM,方便观察其随时间累积,各指标的运行轨迹,以此确定分析入口。

 

方向:

1、短时间内有大量的获取连接请求,超过了连接池配置的最大阈值,导致获取不到连接。

2、活跃连接没有放入连接池复用,同时占用连接数的统计名额(代码使用不规范未释放DB连接、druid参数配置不合理或者其本身存在bug等)。

 

现象:

从生产日志分析,并结合Jconsole关键指标的轨迹和druid的监控数据,得到如下现象:

1、没有可用的连接持续时间很长,从当天19点左右第一次出现问题之后,直到服务重启(持续时间12小时以上),该节点再也不能获取到连接

2、jvm内存指标保持在合理运行区间,没有异常,但线程有泄露(随着时间累积,线程数量缓慢上升)

 

3、DB连接获取不到前,日志中发现有线程创建失败(java.lang.OutOfMemoryError: unable to create new native thread

4、DB连接获取不到的同时,伴随着执行线程(http-bio-8080-exec-244等,来源于tomcat维护的线程池)莫名退出(追踪DB持久化的处理失败任务的日志轨迹得出)

5、存在比较多耗时长的SQL操作

 

分析:

通过现象1,并结合服务在重启前长时间内的请求流量指标(不大),可以排除方向1。

 

基本认定方向2。

经过代码梳理,数据库连接均通过druid管理维护,没有自主获取连接的代码;

生产druid的主要参数配置如下:

initialSize:10
minIdle:10
maxActive:100
maxWait:60000
timeBetweenEvictionRunsMillis:60000
minEvictableIdleTimeMillis:300000
注:没有配置removeAbandoned/removeAbandonedTimeout/logAbandoned(强制物理断开超过指定时间的连接并记录日志)。
如果配置这些参数,不会发生此问题,但应知道此配置会严重影响druid性能。它们只能作为验证或者发现问题的手段,不能作为常规参数配置。

结合配置参数,进行源码分析(因为之前不知天高地厚的怀疑过druid源码可能存在bug,花费比较大的经历来阅读,虽然方向错误,但收获很大。
真切的看到了其实现机制,不在是想象,以后要多创造机会品读优秀源码),比较深入的了解到其实现细节后,
明确正常情况下,活跃连接执行完操作后,会被立即放回池中待复用。
担当线程池没能正常修改池状态,就会导致其认为该连接一直处于活跃状态,不能被复用。
因为没有空闲连接可用,线程池只能通过创建新的物理连接来满足需要,直到达到池阈值,再也不能创建新的连接。

进一步从DB来验证结论,请DBA抓取事故当日指定用户的登入/登出情况(集群整体数据)。
经过匹配,发现有110个连接登入后,没有登出(2个节点,事故节点连接100,非事故节点连接10),与上面分析结论吻合。

至此,确定方向2是导致问题的原因,并进一步明确是线程突然退出导致的。

 

结论:

随着时间的积累,应用的线程数不断增加(线程使用完未退出),直至线程创建失败(一定的资源环境下,线程的数目是有上限的)或者线程池中某些线程会突然终止,后者造成资源不能正常的释放,从而导致DB连接执行完SQL后(空闲状态),没有返回连接池待复用,连接池认为该连接仍然是活跃状态,新的请求就会去创建新的连接,未正常释放的连接达到阈值后,连接池再也不会去创建新的连接。这样从数据库看,存在大量的空闲连接,但从应用看,却获取不到空闲连接或者创建不了新连接。

那是什么原因导致线程退出的呢?

一个进程中,能创建的线程是有上限的,在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象,同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory。

理论上系统线程内存可用的最大空间为(MaxProcessMemory - JVMMemory - ReservedOsMemory)。

这正好解释了现象2和现象3,也为现象4的出现提供了可能性。

 

方案:

1、进一步定位线程资源溢出的问题,并修复。

2、针对现象5,对SQL进行分析优化,缩短执行时长,让DB连接尽快能够复用,提升系统TPS。

 

不足:

没有在准生产环境进行问题复现(复现有一定难度),并验证方案的有效性,问题的解决不应只停留在理论分析层面,要尽量创造环境来验证分析的过程和结论。

 

以上是关于这一生产事故的分析处理过程。

备注:druid源码分析基于1.0.13版本

转载于:https://www.cnblogs.com/yooung/p/10448201.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值