在上一篇文章中,我們介紹了彈性資料庫連接失效的背景,並探討了HikariCP連接池探活策略的相關內容。在本文中,我們將會繼續探討另一個線上常用的連接池——Druid,併為您介紹如何在使用Druid時實現最佳實踐的彈性資料庫連接池探活策略。 ...
前言
在上一篇文章中,我們介紹了彈性資料庫連接失效的背景,並探討了HikariCP連接池探活策略的相關內容。在本文中,我們將會繼續探討另一個線上常用的連接池——Druid,併為您介紹如何在使用Druid時實現最佳實踐的彈性資料庫連接池探活策略。
Druid
Druid的版本迭代更新比較快,同時探活配置的參數也比較多,這導致即使是相同的參數在不同的版本中達到的效果也可能不一樣。但與探活相關的邏輯實現只存在源碼里的兩個函數里, 我們先列舉一下跟Druid探活相關的參數,在具體看一下源碼的實現對這些參數的使用。日後我們在開發中遇到配置探活不生效的情況下,可以看一下對應版本源碼來判斷自己的探活是否配置正確。
下麵是與Druid探活相關的參數:
參數名稱 | 說明 | 預設值 |
---|---|---|
initialSize | 初始化時建立物理連接的個數。初始化發生在顯示調用init方法,或者第一次getConnection時。 | 0 |
minIdle | 最小連接池數量。 | 0 |
maxActive | 最大連接池數量。 | 8 |
testOnBorrow | 申請連接時執行validationQuery配置的SQL檢測連接是否有效,做了這個配置會降低性能。 | false |
testOnReturn | 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。 | false |
testWhileIdle | 建議配置為true,不影響性能,並且保證安全性。在連接池中申請連接的時候檢測,如果空閑時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。 | 大多數版本為True |
timeBetweenEvictionRunsMillis | 1) Destroy線程會檢測連接的間隔時間,每隔這個值的時間就會執行一次DestroyTask。 2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明。 | 大多數版本是1分鐘 |
keepAlive | 連接池中的minIdle數量以內的連接,空閑時間超過minEvictableIdleTimeMillis,則會執行探活操作此參數在1.0.28以上的版本才支持 詳細說明參考官方文檔。 | false |
keepAliveBetweenTimeMillis | 配合keepAlive使用在低版本不支持,如果空閑時間小於timeBetweenEvictionRunsMillis但大於keepAliveBetweenTimeMillis扔執行探活操作 | 大多數版本是2分鐘 |
validationQuery | 用來檢測連接是否有效的sql,要求是一個查詢語句。 | select 1 |
validationQueryTimeout | 單位:秒,檢測連接是否有效的超時時間。底層調用jdbc Statement對象的void setQueryTimeout(int seconds)方法 | |
minEvictableIdleTimeMillis | 連接空閑時間大於該值時關閉空閑連接大於minIdle的連接,類似hikaricp的idleTimeout | 30分鐘 |
maxEvictableIdleTimeMillis | 連接空閑時間大於該值時不管minIdle都關閉該連接,類似hikaricp的maxlifetime(低版本不支持) | 7小時 |
Druid的探活主要有以下兩個函數來實現:
- com.alibaba.druid.pool.DruidDataSource#getConnectionDirect
getConnectionDirect是每次從連接池中取連接時會被調用的函數。我們從下麵的代碼中可以看出,如果testOnBorrow為true,則每次獲取連接之前都會檢測連接是否有效。如果testOnBorrow為false且testWhileIdle為true,則需要判斷連接的空閑時間是否超過timeBetweenEvictionRunsMillis設置的值,如果超過則進行探活檢測。失效的連接會被丟棄,並且會補充到連接池的minIdle數量。timeBetweenEvictionRunsMillis在大多數版本中的預設值為1分鐘。只要這個值設置的時間小於十分鐘,並且保證testWhileIdle開啟,就能保證拿不到網關關閉的失效連接。
在不支持keepalive的低版本中,只能依靠testOnBorrow或testWhileIdle來進行探活。建議配置testWhileIdle來進行探活。在高併發的場景下,這種方式的性能消耗會更小一些。
- com.alibaba.druid.pool.DruidDataSource#shrink(boolean, boolean)
在下麵的代碼中我們可以看出,shrink方法是在DestroyTask線程的run方法中調用的,用於銷毀連接池中的連接。如果timeBetweenEvictionRunsMillis大於0,則每隔這個時間間隔就會調用destroyTask.run(boolean, boolean)方法,即執行shrink方法。
從上面的代碼中可以看出,shrink方法會使用keepAlive參數。需要註意的是,在不同版本的Druid中,keepAlive參數的支持和實現邏輯可能不同。官方建議在使用keepAlive參數時,應該使用1.1.21以上的版本。儘管官方文檔中說明瞭空閑時間超過minEvictableIdleTimeMillis,就會執行探活操作,但是在高版本中,這個探活操作的執行時間也受到了keepAliveBetweenTimeMillis參數的影響。因此,在高版本中,如果想要正確地使用keepAlive參數,就需要瞭解其在具體版本中的實現邏輯。
下麵代碼是1.1.10和1.1.21版本中關於shrink方法的源碼對比:
首先看一下1.1.10版本的源碼,它首先會判斷連接空閑時間是否大於minEvictableIdleTimeMillis,如果是,則接下來進行第二步的判斷:是否是多於minIdle的空閑連接。如果是,就將這些連接加入到驅逐連接的數組中,以便進行後續的驅逐操作。如果不是,就再次判斷連接空閑時間是否大於maxEvictableIdleTimeMillis,如果是,則將這些連接加入到驅逐連接的數組中。如果也不是,則進行最後的判斷:是否開啟了keepAlive配置。如果開啟了,就將這些連接加入到保活連接數組中,以進行後續的探活操作。
在1.1.21版本中,shrink方法的總體邏輯與1.1.10版本類似,但是新增了一個名為keepAliveBetweenTimeMillis的參數。這個參數決定了使用keepAlive進行探活的時間間隔,其預設值為2分鐘,keepalive開啟且空閑時間大於這個值會進行探活。
另一個不同點是,在進行探活操作時,1.1.10版本僅會關閉無效的連接,但1.1.21版本則更進一步,除了關閉無效連接外,還會自動添加連接以達到minIdle的最小連接數。
1.1.10 1.1.21
總結,druid的探活參數在1.0.28版本之前沒有定時的探活功能只能在每次拿到連接前進行檢測是否有效,建議配置testWhileIdle為true在高併發情況下不會太影響性能,如果對可用性要求高的可以開啟testOnBorrow,以在每次獲取連接時檢測連接的有效性。在高版本中可以用keepAlive參數對連接進行保活。針對線上使用Druid連接池的應用建議使用支持keepAlive的1.1.21或者更高版本。
JED配置模版:
Druid1.1.10
<propertyname="testWhileIdle"value="true"/>
<propertyname="validationQuery"value="SELECT 1"/>
<propertyname="timeBetweenEvictionRunsMillis"value="30000"/>
<propertyname="minEvictableIdleTimeMillis"value="300000"/>
<propertyname="keepAlive"value=true/>
此版本支持keepAlive可以配置minEvictableIdleTimeMillis時間小於10分鐘,能夠高效的進行探活防止網關關閉連接。
Druid1.1.9
同1.1.10
Druid1.0.9
<propertyname="testWhileIdle"value="true"/>
<propertyname="validationQuery"value="SELECT 1"/>
<propertyname="timeBetweenEvictionRunsMillis"value="30000"/>
<propertyname="minEvictableIdleTimeMillis"value="300000"/>
此版本不支持keepAlive只能在獲取連接對象的時候檢測,對可用性高的也可以開啟testOnBorrow。
作者:京東零售 王雷鑫
來源:京東雲開發者社區 轉載請註明來源