前段时间,系统数据库完成了迁移,从自建数据库集群迁移至云资源池环境重保区,进一步提升系统稳定性。迁移后,发现个别系统流水线定时任务,会出现一直保持created状态,不消费的情况。
问题分析
通过查看消息队列,未发现异常消息的情况。那么就有两种可能:
- 考虑消息是否未加入消息队列
- 考虑消息是否异常中止
由于消息消费是异步执行,未通过接口调用,无法通过skywalking
进行日志追踪,所以只能到生产上查看日志,同时配置了加入消息队列和消息队列消费的异步异常邮件通知,
成功捕获到了问题:
wait timeout
是数据库的一个设置,通过下面这条 SQL可以查看。
show variables like '%wait timeout%'
查看了资源池的配置是1800,单位s。意义是连接客户端的超时时间,在一个连接空闲超过这个时间时,mysql会自动关闭这个连接。
那么问题出现了,现在的数据库连接池框架都是使用连接池的,连接会保持最小的连接个数,当然也会配置连接超时删除的参数,如果超过了连接空闲的最大时间就会关闭连接。
如果框架的最大连接时间大于数据库的最大连接时间,当数据库的连接关闭后,数据库连接池还保持这个连接,那么再使用这个连接时,就会出现无法连接的情况。
系统使用的数据库连接框架为Druid
, minEvictableldleTimeMillis
配置为 300000 ms
, maxEvictableldleTimeMilis
未配置。默认值设置为7小时。这也验证了是这个问题,之前自建数据库集群的 wait_ timeout
默认是28800s,即为8个小时。
回过头来分析之前的场景(个别系统流水线定时任务,会出现一直保持created状态,不消费的情况),去xxljob查看了调度日志,报错确实是被分配到了绿环境(系统为蓝绿部署)的机器执行,数据库连接末保持导致出现了这个问题。
经过分析,成功了定位了问题,那就好办了。显然可得,有两种解决办法:
- 一种是在使用连接池的某个连接之前,先检测这个连接是否可用
- 另一种就是在Mysql关闭连接之前,Druid先主动把连接关闭了,这样保证了在连接池中的连接是没有Mysql 关闭的(都是可用的)。
在这之前,先了解几个Druid的参数:
- testOnBorrow :在获取连接的时候测试,每次从连接池获取连接都会测试连接(执行测试语句)是否可用,如果不可用获取新的连接,会严重影响性能。
- timeBetweenEvictionRunsMillis:间隔指定时间检查连接
池中的连接是否可用。 - testWhileldle:获取连接的时候,如果连接空闲时间超过timeBetweenEvictionRunsMillis, 会检测连接是否可用。
- minEvictableldleTimeMillis:若当前连接池中的连接数量
已经超过了配置的最小连接数,并且有超过配置的minEvictableldleTimeMillis时间的空闲连接,就会被关闭。 - maxEvictableldleTimeMillis:如果当前连接池中有超过配置的maxEvictableldleTimeMilis时间的空闲连接,不管怎样也会关闭这个连接。
- 使用前检测连接是否可用
配置 testOnBorrow为True,会严重影响性能。
配置 testOnBorrow为false, testwhileldle为true,据说这样不会影响性能。
testonBorrow优先级比testwhileldle高,也就是说同时配置两个参数为true,testWhileldle不会生效(也没有生效的必要了)。
2.保证在数据库关闭连接之前主动关闭连接
其实也就是数据库wait-timeout>max(minEvictableldleTimeMillis+timeBetweenEvictionRuns Mills, maxEvictableldleTimeMillis+timeBetweenEvictionRunsMillis)
,保证在下一次检查连接之前,数据库不会主动关闭连接。
经与运维老师沟通,wait_timeout
是个推荐值,不建议修改,所以调整了Druid参数maxEvictableldleTimeMillis
的值,週整力1700000 ms。也就是之前未配置默认为8小时的maxEvictableldleTimeMillis
设置为1700000ms。问题就得到解决了。