druid Communications link failure报错处理手册

3,516 阅读4分钟

现象

日志报错:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

原因

从数据库连接池拿到了已经关闭的连接,导致报错。druid有定时任务进行空闲连接的检测和回收,当连接时长超过mysql的连接超时时间时,会被mysql强制断开,而如果此时数据库连接池并没有检测到连接已断开并交给应用去使用就会导致报错。

1、查看mysql服务器端的连接超时时间,单位秒,默认时8小时

show global variables like 'wait_timeout'
show global variables like 'interactive_timeout'

2、druid的存在几个关键参数

minIdle: 最小连接池数量

minEvictableIdleTimeMillis: 单位毫秒,默认30分钟,如果连接池中空闲连接大于minIdle数量,且连接空闲时间超过该值,则进行连接的回收操作。

maxEvictableIdleTimeMillis: 单位毫秒,默认7小时,如果连接空闲时间超过该值则强制关闭。

timeBetweenEvictionRunsMillis: 单位毫秒,两个作用:1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明

testWhileIdle: 不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。

validationQuery: 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用

3,当以上参数配置不合理时,1)minEvictableIdleTimeMillis过大 空闲连接一直没有被回收,而超过mysql连接超时时间被强制回收后,则此时获取到的连接会导致报错。2)timeBetweenEvictionRunsMillis配置过大,则在该时间窗口内获取到的连接可能报错。

验证:

数据库超时时间设为30s

set global wait_timeout=30;
1, test-while-idle false

条件:minEvictableIdleTimeMillis和maxEvictableIdleTimeMillis设置的足够大,test-while-idle设置为false

分析:执行第一次请求建立数据库连接,等待30s后执行第二次请求,此时连接已被数据库断开,因为连接池minEvictableIdleTimeMillis足够大,所以不会关闭空闲连接,且test-while-idle为false不会在请求时检测连接,所以预期会报错

      maxActive: 20   
      initialSize: 1      
      minIdle: 1       
      maxWait: 60000   
      time-between-eviction-runs-millis: 40000
      minEvictableIdleTimeMillis: 1800000
      maxEvictableIdleTimeMillis: 2400000
      validationQuery: SELECT 1
      test-while-idle: false  
      test-on-borrow: false 
      test-on-return: false 

bcb7de3065924c9cacbc4a28474df8d4_tplv-k3u1fbpfcp-zoom-1.image

2, test-while-idle true,time-between-eviction-runs-millis<30

条件:minEvictableIdleTimeMillis和maxEvictableIdleTimeMillis设置的足够大;

test-while-idle设置为true,time-between-eviction-runs-millis<30s

分析:执行第一次请求建立数据库连接,等待30s后执行第二次请求,此时连接已被数据库断开,因为连接池minEvictableIdleTimeMillis足够大,所以不会关闭空闲连接,test-while-idle为true会检测空闲超过time-between-eviction-runs-millis的连接,且time-between-eviction-runs-millis<30s, 等待30秒后进行第二次请求时会执行连接有效性检测抛弃无效连接,所以总是能拿到有效连接,不会报错。

      maxActive: 20   
      initialSize: 1      
      minIdle: 1       
      maxWait: 60000   
      time-between-eviction-runs-millis: 20000
      minEvictableIdleTimeMillis: 1800000
      maxEvictableIdleTimeMillis: 2400000
      validationQuery: SELECT 1
      test-while-idle: true  

可以看到第二次请求druid新建了一条连接而不是使用连接池已有的连接。

2.image

3,test-while-idle true,time-between-eviction-runs-millis>30

条件:minEvictableIdleTimeMillis和maxEvictableIdleTimeMillis设置的足够大;

test-while-idle设置为true,time-between-eviction-runs-millis>30s

分析:执行第一次请求建立数据库连接,等待30s以后执行第二次请求,此时连接已被数据库断开,因为连接池minEvictableIdleTimeMillis足够大,所以不会关闭空闲连接,test-while-idle为true会检测空闲超过time-between-eviction-runs-millis的连接,且time-between-eviction-runs-millis>30s, 分以下两种情况

      maxActive: 20   
      initialSize: 1      
      minIdle: 1       
      maxWait: 60000   
      time-between-eviction-runs-millis: 40000
      minEvictableIdleTimeMillis: 1800000
      maxEvictableIdleTimeMillis: 2400000
      validationQuery: SELECT 1
      test-while-idle: true  

1)等待30秒且小于40秒,由于此时空闲时间<time-between-eviction-runs-millis ,所以获取连接时不会执行有效性质检测,所以依然会报错

31.image

2)等待40秒后进行第二次请求时会执行连接有效性检测抛弃无效连接,所以总是能拿到有效连接,不会报错。

32.image

4,test-while-idle false,

minEvictableIdleTimeMillis设置为40,minIdle设置为0,

      maxActive: 20   
      initialSize: 1      
      minIdle: 0       
      maxWait: 60000   
      time-between-eviction-runs-millis: 1000
      minEvictableIdleTimeMillis: 40000
      maxEvictableIdleTimeMillis: 2400000
      validationQuery: SELECT 1
      test-while-idle: true  

1)等待40秒执行第二次请求操作,则满足如果连接池中空闲连接大于minIdle数量,且连接空闲时间超过该值,则进行连接的回收操作,预期不会报错。

2)等待35秒执行第二次请求,则不满足空闲时间大于40秒,预期会报错

4.image

5,其他情况:长事务,time-between-eviction-runs-millis过大,minEvictableIdleTimeMillis和maxEvictableIdleTimeMillis大于wait_timeout等

解决方案

1,开启testWileIdle参数,在每次获取连接的时候进行连接检测,validationQuery不能为空,否则配置无效

2,优化默认参数 minEvictableIdleTimeMillis<maxEvictableIdleTimeMillis<mysql wait_timeout,优化timeBetweenEvictionRunsMillis值,使连接池能够尽早检测到空闲连接。