调查问题: DruidDataSource报GetConnectionTimeoutException异常
最近生产环境经常发生数据库连接超时的情况,具体的错误信息如下:
GetConnectionTimeoutException,
这个异常是在getConnectionDirect的1394行:poolableConnection = this.getConnectionInternal(maxWaitMillis); 这一句触发;
到下面是getConnectionInternal在超过1秒以后抛出了GetConnectionTimeoutException。
使用arthas调查DruidDataSource
tt -t com.alibaba.druid.pool.DruidDataSource *
tt -i 1099 -w 'target.connections'
tt -i 1099 -w 'target'
出问题的一行代码是:
后来,我对这个pollLast()进行了查询,了解到这就是等待获取连接,但是一直获取不到,超过1秒然后异常了。
接下来我的思路是,继续trace pollLast这个函数,但是经过查询发现没必要了。原因是,connections数组一直是空的,说明创建连接的线程一直没创建出来,导致获取不到,他们之间是通过信号来控制的。
接下来我就一直在想为什么创建不出来,后来发现rn2的maxWait设置跟其它微服务不一致,其它一般是6000后者60000,只有rn2少数几个设置为了1000(1秒)。
然后是就尝试去trace createPhysicalConnection这个函数,如果这个创建时间过程,那就实锤了。
Druid默认是懒加载
https://github.com/alibaba/druid/issues/3051
Druid的常见错误
- wait millis 60000, active 5, maxActive 5
- wait millis 60000, active 0, maxActive 20, creating 1
- socket read time out
其中,第一个是没有关闭连接,第二个是懒加载,关键点在那个creating 1,获取连接时还要创建,可以修改为立即加载方式;第三个的连接池的超时时间可以更长一点。
对于本次rn2的问题,其实就是改maxWait就行。
进一步学习到东西1
watch -b com.alibaba.druid.pool.DruidDataSource getConnectionInternal '{params,returnObj,throwExp, target}' -n 20 -x 3 '#cost>900' >> watch_b.txt &
watch com.alibaba.druid.pool.DruidDataSource getConnectionInternal '{params,returnObj,throwExp, target}' -n 20 -x 3 '#cost>900' >> watch_s.txt &
trace com.alibaba.druid.pool.DruidDataSource getConnectionInternal -n 5 --skipJDKMethod false '#cost>900' >> trace.txt &
tt -t com.alibaba.druid.pool.DruidDataSource getConnectionInternal '#cost>900' >> tt.txt &
trace com.alibaba.druid.pool.DruidAbstractDataSource createPhysicalConnection -n 5 --skipJDKMethod false '#cost>900' >> trace_createPhysicalConnection.txt &
今天,第一次学习了arthas的”后台异步任务“。由于生产环境的某些异常是偶发的,可能几小时,后者几天才能触发一次。我们不可能一直盯着屏幕观察,异步任务完美地解决了这个需求。
进一步学习到东西2
arthas的quit或者exit并不是真正的退出,进程还在运行,stop才是真正的结束进程。
进一步了解到,但是没有尝试的东西
1、arthas通过反射修改object的field的值,这可以方便做线上测试。
额外知道的东西
只要是我花了时间,经过思考解决过的问题,都值得记录一下。
在trace com.alibaba.druid.pool.DruidDataSource getConnectionInternal -n 5 --skipJDKMethod false '#cost>900' >> trace.txt &时,我发现getConnectionInternal被连续调用了两次。刚开始,我猜测这是由于接口调用了两次导致接口也被调用了两次,于是我去检查了时间点的接口,发现只有一次异常,只有一次调用。我还检查了代码中的mapper文件(怀疑写重复了),也没问题。最后我开始比较字符串,没想到真的比较处理问题。
com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 1000, active 0, maxActive 10, creating 1, createElapseMillis 1000
com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 1000, active 0, maxActive 10, creating 1, createElapseMillis 2012
仔细看,最后的createElapseMillis时间不一样,没错,你猜出来了么?是retry了一次,所以是DruidDatasource在获取连接失败后进行了重试,至此,真相大白。
转载请注明:牛哥678 » 调查问题: DruidDataSource报GetConnectionTimeoutException异常