彈性資料庫連線池探活策略調研(三)——DBCP

2023-09-08 12:02:14

前言

在之前的文章中,我們介紹了彈性資料庫連線失效的背景,並探討了HikariCP、Druid連線池探活策略的相關內容。在本文中,我們將會繼續探討另一個線上常用的連線池——DBCP,併為您介紹如何在使用DBCP時實現最佳實踐的彈性資料庫連線池探活策略。

DBCP

DBCP有兩個版本:1.x和2.x(也稱為DBCP2)。DBCP 2基於Commons Pool 2,相比1.x版本,在效能、JMX支援和其他許多方面都有所提高。由於DBCP 2.x與DBCP 1.x不是二進位制相容,所以升級到2.x的使用者應該知道Java包名稱已經改變,以及Maven座標。

首先我們先列出關於DBCP探活相關的引數:

引數名稱 說明 預設值
initialSize 初始化時建立物理連線的個數。 0
minIdle 最小空閒連線:連線池中容許保持空閒狀態的最小連線數量,低於這個數量將建立新的連線,如果設定為0則不建立 0
maxIdle 最大空閒連線:連線池中容許保持空閒狀態的最大連線數量,超過的空閒連線將被釋放,如果設定為負數表示不限制 8
maxActive/maxTotal 最大活動連線:連線池在同一時間能夠分配的最大活動連線的數量,超過這個值的請求進入等待佇列, 如果設定為非正數則表示不限制(1.x版本 maxActive 2.x版本maxTotal) 8
testOnBorrow 指明是否在從池中取出連線前進行檢驗,如果檢驗失敗,則從池中去除連線並嘗試取出另一個 true
testOnReturn 指明是否在歸還到池中前進行檢驗。 false
testWhileIdle 指明連線是否被空閒連線回收器進行檢驗。如果檢測失敗,則連線將被從池中去除.注意: 設定為true後如果要生效,validationQuery引數必須設定為非空字串 false
timeBetweenEvictionRunsMillis 驅逐連線的執行緒執行的時間間隔,以毫秒為單位. 如果設定為非正數,則不執行空閒連線回收器執行緒 -1
validationQuery 用來檢測連線是否有效的sql,要求是一個查詢語句。 select 1
validationQueryTimeout 單位:秒,檢測連線是否有效的超時時間。底層呼叫jdbc Statement物件的void setQueryTimeout(int seconds)方法
minEvictableIdleTimeMillis 連線在池中處於空閒狀態的最小時間,超過這個時間會被驅逐驅逐。 30分鐘
softMinEvictableIdleTimeMillis 這個引數與minEvictableIdleTimeMillis相比是這個引數受minIdle的限制,當到達這個值的時候只會驅逐大於minIdle的連線數 -1
numTestsPerEvictionRun 在每次空閒連線回收器執行緒執行時檢查的連線數量。 3

DBCP 和與Druid 的探活設定相比,儘管它們的許多引數名字和功能相似,但在細節和預設值上存在不同之處。例如,testWhileIdle 引數在 Druid 中用於判斷是否在申請連線時開啟探活,且需大於 timeBetweenEvictionRunsMillis 引數值。而在 DBCP 中,該引數在驅逐連線時進行判斷,若開啟,則直接進行驗證,類似Druid中的keepAlive引數。兩個連線池中,驅逐空閒連線的時間間隔都受到 timeBetweenEvictionRunsMillis 引數的控制。此外,testOnBorrow 引數的功能相同,但預設值有所不同。

另外在DBCP在驅逐執行緒中也受numTestsPerEvictionRun引數影響,這個引數是指每次驅逐執行緒執行時驅逐連線的個數,不會一次檢查池內全部的連線。此外DBCP的minEvictableIdleTimeMillis跟Druid不同超時驅逐的連線數不受minidle控制。

下圖是DBCP1.4.0的驅逐連線執行緒的原始碼:org.apache.commons.pool.impl.GenericObjectPool#evict

我們可以從原始碼中看到驅逐的連線個數從getNumTests獲取,getNumTests返回的是連線池的現有size和numTestsPerEvictionRun的最小值。驅逐過程的第一步先判斷空閒時間是否超過minEvictableIdleTimeMillis,沒有的話再判斷softMinEvictableIdleTimeMillis是否超時和現有的連線是否大於minIdle,第三個if是判斷testWhileIdle的設定為true時且上面沒有回收該連線,在第四步的時候對此連線進行探活。

總結:DBCP在各個版本中對探活變動不大,一般都是在驅逐連線數時可以使用testWhileIdle來進行探活,驅逐執行緒執行的間隔時間是timeBetweenEvictionRunsMillis引數的值,此外numTestsPerEvictionRun引數是每次驅逐執行緒的個數,因此我們只要使用這兩個引數設定的可以在10分鐘之內對池內所有連線(最大值為maxActive/maxTotal)進行探活就能有效避免JED閘道器的失效連線。

總的來說,DBCP在不同版本中對探活的實現方式變化不大。通常情況下,可以通過在驅逐連線時使用testWhileIdle引數來進行連線的探活。驅逐執行緒的執行間隔時間受timeBetweenEvictionRunsMillis引數的控制,而numTestsPerEvictionRun引數則決定了每次驅逐執行緒可以處理的連線數。建議numTestsPerEvictionRun設定的值和maxActive/maxTotal一致,並設定timeBetweenEvictionRunsMillis小於10分鐘能夠保證對所有連線進行探活,避免拿到閘道器失效的連線。

此外,應用使用DBCP時,預設開啟testOnBorrow引數一般可以有效避免拿到失效的連線,而Druid預設不開啟testOnBorrow引數。關於是否開啟testOnBorrow引數,應用可以自行評估。雖然開啟testOnBorrow引數會在每次拿到連線前進行連線驗證,損耗一小部分效能,但是這樣能夠及時銷燬無效連線並重建新連線,在遇到JED閘道器故障重啟時能夠有效避免應用報錯。

JED設定模版:

DBCP1.4

<propertyname="minIdle"value="5"/> 
<propertyname="maxActive"value="10"/> 
<propertyname="testWhileIdle"value="true"/>    
<propertyname="validationQuery"value="SELECT 1"/>    
<propertyname="timeBetweenEvictionRunsMillis"value="300000"/>    
<propertyname="numTestsPerEvictionRun"value="10"/>   

DBCP2.2.0

<propertyname="minIdle"value="5"/> 
<propertyname="maxTotal"value="10"/> 
<propertyname="testWhileIdle"value="true"/>    
<propertyname="validationQuery"value="SELECT 1"/>    
<propertyname="timeBetweenEvictionRunsMillis"value="300000"/>    
<propertyname="numTestsPerEvictionRun"value="10"/>   

DBCP2.1.1

同2.2.0

總結

本文以JED的閘道器超時報錯為背景,對常見的資料庫連線池進行了調研,並介紹了連線池探活相關的引數和探活邏輯。通過本文的內容,讀者應該瞭解到不同連線池的探活內容,可以根據不同的引數設定連線池,有效避免應用拿到閘道器關閉的連線。本文提供了在JED資料庫中的連線池設定模板,讀者可以根據自己的應用需求進行調整。

作者:京東零售 王雷鑫

來源:京東雲開發者社群 轉載請註明來源