最新消息:

调查问题: DruidDataSource报GetConnectionTimeoutException异常

MySQL niuge678 2400浏览 0评论

调查问题: 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的常见错误

  1. wait millis 60000, active 5, maxActive 5
  2. wait millis 60000, active 0, maxActive 20, creating 1
  3. 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异常

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址