雲計算

針對數據庫連接池到DRDS連接探活的優化

近期在給某專有云客戶進⾏雲產品應⽤性能優化分析時,發現了⼀個有趣的關於DRDS使⽤層⾯的問題,這⾥給⼤家分享⼀下。
使⽤過DRDS產品的同學都知道在DRDS中,未分庫分表的數據表會存儲在“0號庫”上,對於這些表操作的SQL會被分發到“0號庫”上執⾏。所以⼀般情況下,0號庫所在實例的壓⼒會⽐其它實例的壓⼒稍⼤⼀些。近期分析該客戶的數據庫性能時,發現客戶使⽤的DRDS下0號庫所在的RDS實例的壓⼒明顯⽐其它RDS實例⾼出許多。

1.jpg
圖1:SQL語句平均每秒執行次數及事務數

通過查看0號庫所在的RDS實例的執⾏SQL發現,有⼤量的 SELECT 'x' 的查詢語句。檢查應⽤側代碼後發現,這個查詢語句是應⽤側連接池配置的連接探活SQL,所有的連接池實現⼏乎都有這個功能,可以通過探活SQL檢測連接當前是否可⽤。
那麼問題來了:

  1. 為什麼只有0號庫所在RDS上會有⼤量此類的語句?
    DRDS中不帶表名的(⽐如 SELECT 'x')SQL和show命令都會被下發到0號庫執⾏。

  2. 對於客戶端來說這種連接檢測是否有⽤?

答案⼀定是有⽤的,因為如果因⽹絡閃斷或其它原因導致的連接狀態不可⽤,即使獲取到了連接對象,也不能進⾏數據訪問操作。所以這個檢測是有必要的,但對於使⽤DRDS作為數據源的場景來說,⽬前配置的檢測⽅式是存在問題的。
對於傳統的數據庫使⽤⽅式,客戶端是直接連接到底層數據庫的,如下圖。探活SQL是直接發到連接的數據庫執⾏,這種場景下使⽤ SELECT 'x' 檢測客戶端到數據庫的連接是沒有問題的。

2.jpg
圖2:客戶端連接到數據庫

⽽對於使⽤DRDS作為數據源的場景來說,探活語句在發送到DRDS服務後,會被轉發到0號庫執⾏,這就意味著這個探活SQL實際上檢測的是客戶端-->DRDS-->0號庫的鏈路是否正常。

3.jpg
圖3:客戶端通過DRDS連接到數據庫

這⼀點可以從DRDS上看 SELECT 'x' 的執⾏計劃得到證實,如下:

4.jpg
圖4:執⾏結果1

實際上,這樣的數據源連接檢測是沒有意義的。因為:

  • 第⼀,數據源後端實際上只檢測了DRDS到0號庫的連接狀態,DRDS到其它分庫的連接狀態並未檢測。但真正執⾏SQL時,DRDS是有可能將解析後的SQL下發到其它分庫上執⾏的。

  • 第⼆,客戶端探活SQL的作⽤主要是為了保證客戶端連接池與數據源之間的連接是可⽤的。對於數據源背後的情況應該由數據源本身維護,即由DRDS本身到RDS的連接池保障連接可⽤性,⽽不應該通過客戶端的探活功能來保證。

明⽩以上內容後,我們解決問題的⽅案就⽐較清楚了,實際上我們只需要讓客戶端連接池檢測客戶端到DRDS的連接狀態即可。那有沒有這樣的檢測⽅法呢?
答案當然是有的,經過與DRDS研發同學確認,將探活SQL修改為 SELECT 'x' FROM dual 即可。
修改後,再次在DRDS查看執⾏計劃,如下:

5.jpg
圖5:執⾏結果2

在應⽤側修改連接池的探活SQL配置後,從0號庫所在實例上看,已經看不到探活SQL的執⾏記錄,⽽且從修改前和修改後0號庫所在實例的壓⼒來看,效果也⽐較明顯,0號庫的壓⼒相⽐之前下降了⼤概80%左右。

6.jpg
圖6:SQL語句平均每秒執行次數及事務數2

⾄此,0號庫壓⼒過⾼的問題解決了,下⾯我們聊聊為什麼會有⼤量的探活語句出現。
探活機制實際上是數據源連接池通⽤的⼀種檢測機制,可以檢測連接池內的連接對象是否真的可⽤。拿Druid連接池舉例,探活SQL是通過數據源的 validationQuery 屬性配置的。與之相關的配置屬性還有:testOnBorrow、testWhileIdle、testOnReturn、timeBetweenEvictionRunsMillis、 minEvictableIdleTimeMillis。官⽅解釋如下:

  • testOnBorrow:申請連接時執⾏ validationQuery 配置的探活語句檢測連接是否有效。

  • testWhileIdle:申請連接的時候檢測,如果空閒時間⼤於timeBetweenEvictionRunsMillis ,執⾏ validationQuery 檢測連接是否有效。

  • testOnReturn:歸還連接時執⾏ validationQuery 檢測連接是否有效。

  • timeBetweenEvictionRunsMillis:有兩個含義

1) Destroy線程檢測連接的間隔時間,如果連接空閒時間⼤於等於 minEvictableIdleTimeMillis 則關閉物理連接。
2) testWhileIdle 的判斷依據,詳細看 testWhileIdle 屬性的說明。

  • minEvictableIdleTimeMillis:連接保持空閒⽽不被驅逐的最⼩時間。

⽂章前⾯描述的出現⼤量探活SQL的情況是因為應⽤將連接池的testOnBorrow設置成了true,所以在每次應⽤獲取連接時,都會執⾏ validationQuery 配置的探活語句檢測連接是否有效。雖然通過前⾯的優化步驟,已經降低了0號庫的壓⼒,使探活語句不下發到0號庫執⾏。但探活語句仍會在DRDS實例上執⾏,DRDS實例的壓⼒並未減輕。通過上⾯對Druid數據源屬性配置的說明可以瞭解到,如果將 testOnBorrow 或 testOnReturn 打開,會對系統性能有⼀定的影響,因為每次都會在獲取連接時多執⾏⼀次查詢來檢測連接是否可⽤。因此推薦使⽤如下的配置:

  • testWhileIdle=true【如果獲得的連接為“空閒連接”,則會進⾏探活檢測,如果檢測失敗,會將此連接從連接池移除,嘗試重新從連接池獲取連接】

  • timeBetweenEvictionRunsMillis=60000【Destroy線程每隔1分鐘對連接池內部的空閒時間>= minEvictableIdleTimeMillis的連接進⾏探活檢測,如果檢測失敗,會將連接從連接池移除】

  • minEvictableIdleTimeMillis=60000【如果連接閒置1分鐘,則認為此連接為“空閒連接“】

這樣設置完成後,只有在獲取到“空閒連接”時,才會進⾏探活檢測,⼤⼤降低了業務⾼峰時段的探活頻率。同時,也可通過適當縮短minEvictableIdleTimeMillis 的值,兼顧由於⽹絡閃斷或其它原因導致的連接不可⽤的情況,減少業務出錯的概率,在系統性能和可⽤性之間找到⼀個平衡點。

我們是阿里雲智能全球技術服務-SRE團隊,我們致力成為一個以技術為基礎、面向服務、保障業務系統高可用的工程師團隊;提供專業、體系化的SRE服務,幫助廣大客戶更好地使用雲、基於雲構建更加穩定可靠的業務系統,提升業務穩定性。我們期望能夠分享更多幫助企業客戶上雲、用好雲,讓客戶雲上業務運行更加穩定可靠的技術,您可用釘釘掃描下方二維碼,加入阿里雲SRE技術學院釘釘圈子,和更多雲上人交流關於雲平臺的那些事。

image.png

Leave a Reply

Your email address will not be published. Required fields are marked *