1. 程式人生 > 資料庫 >HikariCP不斷列印WARN日誌Failed to validate connection com.mysql.jdbc.JDBC4Connection@xxxxx (...) Possibly

HikariCP不斷列印WARN日誌Failed to validate connection com.mysql.jdbc.JDBC4Connection@xxxxx (...) Possibly

最終解決方案(結論)

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也有作者在裡面回答,作者的回答主要是檢查mysql的連線時間和是否有獲取並自行關閉了底層的connection。這種情況在我這裡都是沒有的。然後有一個人緊跟著作者說是否是HA代理超時了,然後我就想到我們的資料庫是有用到HA代理的,而且服務如果是通過HA代理連線資料庫的話,那麼maxLifeTime一定是設定為比資料庫超時時間和HA代理超時時間中最小的那一個還要小。然後向DBA詢問HA代理的超時時間,說是300秒,後續我將maxLifeTime改為290_000毫秒之後,發現不再列印錯誤日誌了,至此問題解決

可以很容易想到的是,如果服務與資料庫之間還隔了其他的服務或者代理的話,那麼maxLifeTime也是取決於這些中間服務和資料庫中最小的那個超時時間的,但是maxLifeTime最小隻能到30秒。