天天看點

針對資料庫連接配接池到DRDS連接配接探活的優化

針對資料庫連接配接池到DRDS連接配接探活的優化

1. 問題背景

近期在給某專有雲客戶進⾏雲産品應⽤性能優化分析時,發現了⼀個有趣的關于DRDS使⽤層⾯的問題,這⾥給⼤家分享⼀下。

使⽤過DRDS産品的同學都知道在DRDS中,未分庫分表的資料表會存儲在“0号庫”上,對于這些表操作的SQL會被分發到“0号庫”上執⾏。是以⼀般情況下,0号庫所在執行個體的壓⼒會⽐其它執行個體的壓⼒稍⼤⼀些。近期分析該客戶的資料庫性能時,發現客戶使⽤的DRDS下0号庫所在的RDS執行個體的壓⼒明顯⽐其它RDS執行個體⾼出許多。

針對資料庫連接配接池到DRDS連接配接探活的優化

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

2. 原因分析

通過檢視0号庫所在的RDS執行個體的執⾏SQL發現,有⼤量的 SELECT 'x' 的查詢語句。檢查應⽤側代碼後發現,這個查詢語句是應⽤側連接配接池配置的連接配接探活SQL,所有的連接配接池實作⼏乎都有這個功能,可以通過探活SQL檢測連接配接目前是否可⽤。

那麼問題來了:

1.為什麼隻有0号庫所在RDS上會有⼤量此類的語句?

DRDS中不帶表名的(⽐如 SELECT 'x')SQL和show指令都會被下發到0号庫執⾏。

2.對于用戶端來說這種連接配接檢測是否有⽤?

答案⼀定是有⽤的,因為如果因⽹絡閃斷或其它原因導緻的連接配接狀态不可⽤,即使擷取到了連接配接對象,也不能進⾏資料通路操作。是以這個檢測是有必要的,但對于使⽤DRDS作為資料源的場景來說,⽬前配置的檢測⽅式是存在問題的。

對于傳統的資料庫使⽤⽅式,用戶端是直接連接配接到底層資料庫的,如下圖。探活SQL是直接發到連接配接的資料庫執⾏,這種場景下使⽤ SELECT 'x' 檢測用戶端到資料庫的連接配接是沒有問題的。

針對資料庫連接配接池到DRDS連接配接探活的優化

圖2:用戶端連接配接到資料庫

⽽對于使⽤DRDS作為資料源的場景來說,探活語句在發送到DRDS服務後,會被轉發到0号庫執⾏,這就意味着這個探活SQL實際上檢測的是用戶端-->DRDS-->0号庫的鍊路是否正常。

針對資料庫連接配接池到DRDS連接配接探活的優化

圖3:用戶端通過DRDS連接配接到資料庫

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

針對資料庫連接配接池到DRDS連接配接探活的優化

圖4:執⾏結果1

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

  • 第⼀,資料源後端實際上隻檢測了DRDS到0号庫的連接配接狀态,DRDS到其它分庫的連接配接狀态并未檢測。但真正執⾏SQL時,DRDS是有可能将解析後的SQL下發到其它分庫上執⾏的。
  • 第⼆,用戶端探活SQL的作⽤主要是為了保證用戶端連接配接池與資料源之間的連接配接是可⽤的。對于資料源背後的情況應該由資料源本身維護,即由DRDS本身到RDS的連接配接池保障連接配接可⽤性,⽽不應該通過用戶端的探活功能來保證。

3. 解決方法

明⽩以上内容後,我們解決問題的⽅案就⽐較清楚了,實際上我們隻需要讓用戶端連接配接池檢測用戶端到DRDS的連接配接狀态即可。那有沒有這樣的檢測⽅法呢?

答案當然是有的,經過與DRDS研發同學确認,将探活SQL修改為 SELECT 'x' FROM dual 即可。

修改後,再次在DRDS檢視執⾏計劃,如下:

針對資料庫連接配接池到DRDS連接配接探活的優化

圖5:執⾏結果2

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

針對資料庫連接配接池到DRDS連接配接探活的優化

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

4. 連接配接池參數配置

⾄此,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技術學院釘釘圈子,和更多雲上人交流關于雲平台的那些事。

針對資料庫連接配接池到DRDS連接配接探活的優化