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

簡介: 針對數據庫鏈接池到DRDS鏈接探活的優化

  1. 問題背景

========數據庫

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

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

  1. 緣由分析

========性能

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

  1. 爲何只有0號庫所在RDS上會有⼤量此類的語句?
    DRDS中不帶表名的(⽐如 SELECT 'x')SQL和show命令都會被下發到0號庫執⾏。
  2. 對於客戶端來講這種鏈接檢測是否有⽤?

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

圖2:客戶端鏈接到數據庫阿里雲

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

圖3:客戶端經過DRDS鏈接到數據庫線程

這⼀點能夠從DRDS上看 SELECT 'x' 的執⾏計劃獲得證明,以下:對象

圖4:執⾏結果1

實際上,這樣的數據源鏈接檢測是沒有意義的。由於:

  • 第⼀,數據源後端實際上只檢測了DRDS到0號庫的鏈接狀態,DRDS到其它分庫的鏈接狀態並未檢測。但真正執⾏SQL時,DRDS是有可能將解析後的SQL下發到其它分庫上執⾏的。
  • 第⼆,客戶端探活SQL的做⽤主要是爲了保證客戶端鏈接池與數據源之間的鏈接是可⽤的。對於數據源背後的狀況應該由數據源自己維護,即由DRDS自己到RDS的鏈接池保障鏈接可⽤性,⽽不該該經過客戶端的探活功能來保證。
  1. 解決方法

========

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

圖5:執⾏結果2

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

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

  1. 鏈接池參數配置

⾄此,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 的值,兼顧因爲⽹絡閃斷或其它緣由致使的鏈接不可⽤的狀況,減小業務出錯的機率,在系統性能和可⽤性之間找到⼀個平衡點。

做者:劉維
原文連接 本文爲阿里雲原創內容,未經容許不得轉載

相關文章
相關標籤/搜索