最终解决方案(结论)
maxLifeTime参数需要设置为小于min(数据库的wait_timeout,HA代理的超时时间,其他代理的超时时间);
也就是说要比所有数据库相关服务和数据库服务的超时时间都要小,而不是仅仅是小于数据库的wait_timeout
起因
之前项目中用的都是c3p0的一些连接池,但是根据公司的提供,改为使用HikariCP连接池。但是在项目运行过程中发现项目总是过一段时间就打印日志:
Failed to validate connection com.mysql.jdbc.JDBC4Connection@xxxxx (...)Possibly consider using a shorter maxLifetime value.
解决过程
经过排查和观看源代码,可以发现这个日志实际上并不会导致业务SQl语句的执行出现问题,但是终究还是对语句的执行速度有影响,通过抛出异常再重新获取有效连接肯定是比直接获取有效连接是要慢的。所以在有一些需求之间的空闲时间的情况下,还是打算排查一下这个问题。
按照HikariCP官方和日志中的建议来看,应该是maxLifeTime设置的过长了,所以在询问过DBA之后,得知数据库的wait_timeout设置的是500秒,所以将maxLifeTime连接设置为450_000毫秒,但是仍然还是会打印这种日志,所以这是不行的。
接下来我在网上搜,发现各种的解决都有,大部分都是通过设置更短的时间解决的,但是很少有说为什么设置的这么短就可以解决,而且每个人的数据库配置都是不一样的,所以实际上没什么借鉴意义。那么还是要自己分析一下,可以确定的是出现问题的就是maxLifeTime这个参数。那么这个参数的作用是什么?通过阅读部分HikariCP的源码和对于网上说法的理解来说,maxLifeTime就是用于设置连接在连接池中生存的最大时间的,这个参数一般要比数据库持有连接的时间要短。这是很好理解的,如果数据库主动断开连接,那么底层意义上,连接就已经失效了,一定是会打印这个日志的。但是我明明已经将maxLifeTime设置的比数据库的wait_timeout要短了,然后我一度以为是不是DBA给了错误的timeout时间,向DBA确认之后发现不行。也就是说数据库并不会在maxLifeTime的时间内断开连接。
然后我在搜索的时候发现有一个结果是导向了GitHub的,我想到这个问题应该是很常见的,而且GitHub上作者也会那么我就到GitHub上HikaCP 的issue里面进行搜索,发现了这么一个issue,这个issue也有作者在里面回答,作者的回答主要是检查mysql的连接时间和是否有获取并自行关闭了底层的connection。这种情况在我这里都是没有的。然后有一个人紧跟着作者说是否是HA代理超时了,然后我就想到我们的数据库是有用到HA代理的,而且服务如果是通过HA代理连接数据库的话,那么maxLifeTime一定是设置为比数据库超时时间和HA代理超时时间中最小的那一个还要小。然后向DBA询问HA代理的超时时间,说是300秒,后续我将maxLifeTime改为290_000毫秒之后,发现不再打印错误日志了,至此问题解决。
可以很容易想到的是,如果服务与数据库之间还隔了其他的服务或者代理的话,那么maxLifeTime也是取决于这些中间服务和数据库中最小的那个超时时间的,但是maxLifeTime最小只能到30秒。