问题描述
代码在运行一段时间之后,整体服务就不可用了,但是日志中却没有任何的错误打印。而重启服务之后,服务就可以暂时提供一段时间服务,过一段时间之后再次不可用,而后续的接口请求切面日志都可以输出。
注:我在实操过程中业务中频繁使用了切换数据源等操作以及跨库事务
分析
服务进行重启就可以正常提供功能,说明是某些资源没有释放并且后续的接口请求切面日志都可以输出证明了这一点。接下来需要确定的是什么资源被占用不能够释放就可以定位到问题并解决了。
请求接口后,接口切面的前置日志系统收到了请求并打印了日志,打断点debug后发现,接口请求依然进入了代码中,最后操作进行操作数据库相关操作时,出现了接口pending一支没有返回值,后续仔细断点排查发现,在获取数据连接时
druidDataSource.getConnection();
这一行代码出现了等待卡住,一直没有返回,但重启项目可以解决这个问题。那么就定位到了是druid连接池的问题。
问题定位排查
经过网上资料的查找和自己推断排查,druid默认的maxActive=8 ; 如果并发数大于20 的时候就会出现大量的处于WAITING和 TIMED_WATING 状态的线程。由于默认的最大连接配置为8,可能是连接数不足导致的获取不到链接,一直阻塞住,导致的操作数据库获取connection链接pending,多个线程卡死在获取连接上。为了验证我的猜测,我修改了连接池的配置,修改后配置如下:
//设置获取连接最大等待时间,不再一直等待获取连接
dataSource.setMaxWait(60000);
//是否自动回收超时连接
dataSource.setRemoveAbandoned(true);
//超时时间(以秒数为单位)
dataSource.setRemoveAbandonedTimeout(180);
我后续进行相关接口操作,pending之后等待了一段时间,日志中出现了错误,图片中隐藏一些隐私信息,从图中可以看出
Failed to obtain JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 61428, active 8, maxActive 8, creating 0
说明了默认的8个链接已经被用完了,创建了0,那么很明显就是连接数占用满了导致的pending,那么我们只需要调大最大连接数的配置,并且设置自动回收超时时间以及自动回收超时连接配置开机就能解决
解决方法
//设置最大活跃数16
dataSource.setMaxActive(16);
//设置获取连接最大等待时间,不再一直等待获取连接(视个人情况而定)
dataSource.setMaxWait(60000);
//是否自动回收超时连接
dataSource.setRemoveAbandoned(true);
//超时时间(以秒数为单位)
dataSource.setRemoveAbandonedTimeout(180);