druid 数据库查询间歇性阻塞15分钟
问题描述
在预发布环境测试发现一个奇怪的问题,一开始是一个定时任务执行很慢,由于网络隔离不方便远程调试,选择在每个可能耗时的步骤前后打印详细日志,找出耗时原因。然后在查看日志的时候发现,问题出在一个查询sql,这个查询足足等待了15分钟,但是并不是每次都会这样,并且只要出现这个情况基本就会等待15分钟。
问题分析
检测代码,该查询sql是一个很简单的查询,并且查询的是一个标记表,其中只有几十条数据,所以可以排除数据库慢查询的问题,而且由于是偶发性的,在检查对应的代码后没有发现问题,因此怀疑是否可能是在那一时刻cpu负载过高导致,以前在跑spark任务的时候经常会遇见GC overhead limt exceed的问题,当jvm内存不够时很可能会导致cpu被gc线程占满,这样是会导致用户线程长时间卡顿的。所以使用jstat查看了服务启动以来gc的大致情况,发现服务自启动以来gc所用时间远远不足到15分钟,并且堆内存各个区域占用表现正常,因此基本可以排除gc的问题。
然后又思考其他可能,既然是sql,那还是回到数据库本身考虑,项目使用的是oracle数据库,怀疑被阻塞的那个sql是否被其他事物阻塞了或者表被锁住了,然后去查看V
L
O
C
K
和
V
LOCK和V
LOCK和VSESSION表,发现也被没有这种情况。(实际上被阻塞的是一个 select * from table的语句,没有声明加锁,讲道理即使存在其他事物锁定该表,这个查询应该也不会被阻塞)因此当时并没有结论。
问题再现
问题被搁置2天后,新的问题又出现了,这次的表现是,前端一个查询界面,一开始是OK的,放置一段时间后,再点击查询,迟迟没有响应。而且这问题在开发环境和测试环境没有出现,由于使用了nginx代理,首先排查nginx各项参数和测试环境是否有出入。
然后继续日志埋点,分析日志发现,出现了同样的问题,也是被一个select语句阻塞了15分钟。这下就很奇怪了,这个15分钟到底是哪来的,每次都不多不少15分钟,项目使用的是druid,排查各项参数没有任何可以和15分钟关联的,在程序本身和数据库表这2个因素没有找到问题,选择面向百度编程,无奈之下搜索15分钟关键字,还真找到了类似的情况,该文章标题是《 keepAlive解决druid空闲连接socket timeout 15分钟 》,按照文章的意思,配置了spring.datasource.druid.keep-alive=true参数后,果然就没出现阻塞的情况了。并且在debug日志里找到了一个异常 oracle关闭的连接,结合文章所述,这个异常大概率就是druid检测连接是否有效时执行语句超时导致的。查看druid测试连接的源码方法,在DruidAbstractDataSource 中的testConnectionInternal方法,可知如果测试连接的sql(可配置,oracle一般为select 1 from dual)执行异常,在finally语句中返回false从而销毁该连接重新获取新的连接。
总结
遇到问题不要慌,先晾他个两三天
文中提到的文章连接为 : link