資料庫連線建立是比較昂貴的操作(至少對於 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連線池會在需要分配連線物件給應用程式使用時,先檢查連線物件的狀態。為了檢測連線是否可用,連線池會呼叫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的版本。
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的版本。
同3.2.0版本。
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
作者:京東零售 王雷鑫
來源:京東雲開發者社群 轉載請註明來源