zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

数据库很多异常的会话

2023-03-14 22:44:12 时间

系统的用户操作响应缓慢,数据库很多异常的会话,maxWait这个属性值Druid默认值是-1,导致连接池被占满,数据库连不上一直占用

故障现象

问题影响时间:7月12号 08:21点-09:30点

现象:无法进入系统,已进入系统的用户操作响应缓慢

故障处理过程

08:52 A开始反馈 xx-prod 进不去,数据库很多异常的会话

image.png

08:57-09:15 B进通过grafna和数据库库行了问题的定位,重启应用

image.png



09:18 实例重启成功后,问题依然无法正常服务

09:20-09:25 C通过慢请求定位到申请单查询接口特别慢,定位到是阿里商旅服务的异常

image.png

image.png



09:30 D 重启阿里商旅服务,重启后,实例开始正常工作。

故障原因

  1. 阿里商旅服务异常。通过分析stack,主要是拿不到数据库的链接,导致ice 线程池被占满,导致其他的请求无法请求。导致代码拿不到连接的原因如下:
    1. 分析堆栈信息发现大部分的线程都是阻塞的状态
    2. image.png


b. 分析具体的某个阻塞的线程,发现是因为事务导致的拿不到链接导致的

image.png


c. 通过堆栈信息,可以发现是事务的注解不规范导致的。不应该在类上添加事务的注解,应该加在具体的方法上。

image.png



  1. ice 框架的超时时间设置没有生效。阿里商旅这个服务比较特殊,依赖了钉钉的sdk,只用的jdk1.8,所有的jar包有没有升级到最新的,目前service-common 已经更新到3.2.23,而阿里商旅用的还是1.5.6 。
  2. 代码中的逻辑不是最优的,报销单关联申请单明细的时候,遍历申请单的明细接口,返回了申请单的所有信息,可以修改为只返回前端需要的信息。


首先从stack中可以看出来:

image.png



这里大量的ICE线程在进入了DruidDataSource#takeLast方法后就进入了WAITING的状态;

因此查看了下这个服务用到的Druid版本(1.1.21)对应的代码:

image.png


可以看到notEmpty#await方法让当前线程一直进入WAITING状态等待唤醒。

进入这个分支,说明DruidConnectionHolder连接池容器中没有连接了,因此一直等待有空闲线程去唤醒,同时,这里没有设置超时时间,理论上会一直占用着当前线程,因此线上会出现ICE线程池满的情况(其实是大量线程都在waiting)。

回到最开始的入口方法DruidDataSource#takeLast,进入这个方法的前提是maxWait小于0(默认是-1),如果我们设置maxWait > 0,就会进入有超时时间的分支,线程会尝试获得锁,超过超时时间直接返回null,可以避免线程一直WAITING

image.png

image.png


maxWait这个属性值Druid默认值是-1,可以显式通过设置maxWait的方式来优化,设置一个合理的预期时间值,释放ICE线程去做其他事不要因为数据库连不上一直占用

反思与改进方案

系统的用户操作响应缓慢,数据库很多异常的会话,maxWait这个属性值Druid默认值是-1,导致连接池被占满,数据库连不上一直占用