# 調研背景: 資料庫連接建立是比較昂貴的操作(至少對於 OLTP),不僅要建立 TCP 連接外還需要進行連接鑒權操作,所以客戶端通常會把資料庫連接保存到連接池中進行復用。連接池維護到彈性資料庫(JED)的長連接,彈性資料庫預設不會主動關閉客戶端連接(除非報錯),但一般客戶端到彈性資料庫之間還會有負 ...
調研背景:
資料庫連接建立是比較昂貴的操作(至少對於 OLTP),不僅要建立 TCP 連接外還需要進行連接鑒權操作,所以客戶端通常會把資料庫連接保存到連接池中進行復用。連接池維護到彈性資料庫(JED)的長連接,彈性資料庫預設不會主動關閉客戶端連接(除非報錯),但一般客戶端到彈性資料庫之間還會有負載均衡代理,它們通常為了節約連接資源會在連接空閑10分鐘後主動清理連接,釋放無用的連接資源。這就導致一些用戶的連接池探活參數配置不當,進而拿到是已經失效的連接。客戶端就會報以下錯誤:
基於以上的背景我們根據Java應用常用的連接池的常用版本的連接池探活相關的功能進行了調研,並對每個版本提供了JED配置的模版。目前,常用的連接池版本如下:
HikariCP 3.2.0、 3.4.5、4.0.3
DRUID 1.1.10、1.1.9、1.0.9
DBCP 1.4 、2.2.0、2.1.1
HikariCP
我們第一個章節先來介紹一下HikariCP連接池探活相關的內容:
HikariCP連接池會在需要分配連接對象給應用程式使用時,先檢查連接對象的狀態。為了檢測連接是否可用,連接池會調用isConnectionAlive
方法。如果連接對象是可用的,連接池會將連接對象分配給應用程式使用;如果連接對象不可用,連接池會創建一個新的連接對象,並將新的連接對象分配給應用程式使用。
所以HikariCP連接池的連接對象失效時,連接池只會在日誌中輸出警告信息,建議縮短連接對象的最大生存時間(`maxLifetime`)。但是,這並不會影響程式的正常執行,因為連接池會自動重新創建新的連接對象並分配給應用程式使用。因此,應用程式可以繼續使用連接池中的連接對象,而不會受到失效連接的影響。
雖然使用HikariCP連接池時,如果不配置連接探活,應用程式在拿到失效的連接時不會報錯,但是當應用程式需要執行SQL時,可能會遇到失效的連接,導致需要重新建立連接,增加了額外的性能開銷。這樣就沒有充分發揮連接池的優勢,因為連接池的主要目的是通過重覆使用連接對象來提高應用程式的性能和可伸縮性。
為了最大化發揮連接池的價值,我們就一塊來瞭解一下關於HikariCP探活相關的內容,看看如何利用相關的探活參數更高效地使用連接池。
以下是跟HikariCP探活通用的相關的參數:
參數名稱 | 說明 | 預設值 |
---|---|---|
minimumIdle | 連接池維護的最小空閑連接數 | 5 |
maximumPoolSize | 連接池中能容納的最大連接數 | 10 |
maxLifetime | 此參數用來控制連接在連接池中最大的生命周期,當建立的連接時間超過這個參數時候在空閑狀態就會被銷毀。 | 1800000 (30 minutes) |
idleTimeout | 此參數用來控制連接在連接池中空閑的時間,如果設置8分鐘,就會每隔8分鐘清理一下超過minimumIdle的空閑連接。 | 600000 (10 minutes) |
connectionTestQuery | 這個參數在低版本中只會在從池中提供連接之前執行配置的SQL。這個參數適用於不支持JDBC4 Connection.isValid() API,支持JDBC4以上驅動的建議不要配置。 | none |
keepaliveTime | 該屬性是防止底層網路基礎設施超時斷開,定期驗證連接的有效性,如果連接失效從連接池中剔除。該值必須小於maxLifetime值。4. 0.1以上版本引入的新參數可以結合connectionTestQuery參數來探活。 | 0 (禁用) |
HikariCP連接池的探活代碼如下。可以看到,在探活時,連接池會根據isUseJdbc4Validation屬性的值來決定是否走JDBC API進行探活isUseJdbc4Validation屬性的值是在初始化數據源時根據connectionTestQuery屬性是否為空來賦值的。如果connectionTestQuery屬性為空,isUseJdbc4Validation屬性的值為true,連接池會走JDBC API進行探活。因此,在JDBC 4.0及以上版本中,不建議配置connectionTestQuery屬性進行探活,因為這樣會影響探活的效率。
在HikariCP較低的版本中,無法對連接進行保活,只能在每次獲取連接時驗證連接的有效性。而在4.0.1版本中,引入了keepaliveTime參數,可以定時的對連接進行探活。因此,為避免獲取到已關閉的連接,在低版本中,只能將maxLifetime參數調整到少於10分鐘,才能完全避免拿到網關已經關閉的連接。在4.0.1及以上版本中,可以使用keepaliveTime參數配合connectionTestQuery參數進行連接探活,從而在獲取連接之前就進行探活。這樣可以提高連接的可靠性和穩定性,避免應用程式遇到無效連接的情況。
配置keepaliveTime後我們可以看到每次到配置的時間就會列印出來探活日誌
因此針對線上使用HikariCP的應用推薦使用4.0.1以上支持keepaliveTime的版本。
JED配置模版:
HikariCP3.2.0
spring.datasource.hikari.minimumIdle=5
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.maxLifetime=540000
spring.datasource.hikari.idleTimeout=480000
#JDBC4以上的版本不建議配置connectionTestQuery
spring.datasource.hikari.connectionTestQuery=select 1
低版本中主要保證maxLifetime低於10分鐘能夠完全避免拿到網關已經關閉的連接,但可能會造成頻繁的創建銷毀連接所以建議使用4.0.1以上支持keepaliveTime的版本。
HikariCP3.4.5
同3.2.0版本。
HikariCP4.0.3
spring.datasource.hikari.minimumIdle=5
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.maxLifetime=1800000
spring.datasource.hikari.idleTimeout=600000
#JDBC4以上的版本不建議配置connectionTestQuery
spring.datasource.hikari.connectionTestQuery=select 1
spring.datasource.hikari.keepaliveTime=300000
4.0.1以上的版本中可以把keepaliveTime參數設置小於10分鐘對連接進行探活,就能避免拿到被網關關閉的連接,maxLifetime的時間就可以延長能避免頻繁的創建銷毀連接。
參考文檔: https://github.com/brettwooldridge/HikariCP#readme
作者:京東零售 王雷鑫
來源:京東雲開發者社區 轉載請註明來源