天天看點

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

作者:LinkSLA智能運維管家

openGauss資料庫用戶端連接配接思考

openGauss資料庫企業級資料庫一般采用一主多從的高可用模式。主庫可讀寫,從庫提供可讀能力。之前在裡也探讨過openGauss高可用模式下用戶端通路方式的選擇。

用戶端通路方式

openGauss資料庫主從架構下,用戶端如何連接配接到主資料庫呢?又怎麼做讀寫分離?這個時候就需要讨論下用戶端連接配接資料庫的幾種方式:VIP、DNS和主機清單。因為openGauss資料庫的jdbc驅動裡支援設定多個主機,并提供參數設定隻連主節點還是隻連備節點,這也應對了讀寫分離的需求。

VIP

傳統的VIP模式隻能支援應用連接配接到主節點上,從節點的讀請求是不太好設定的。增加讀VIP的管理對于高可用軟體來說就太複雜了。VIP管理還有一個限制是必須屬于同一網段。對于同城雙中心不能采用相同網段的情況下,VIP漂移就不能實作。

DNS

DNS也具備高可用性,但是隻能檢測到機器IP是否存在,不能檢測openGauss的服務,是以采用DNS的高可用相對來說不太适合資料庫來使用。

主機清單

例如下面這個例子就是隻連主庫的用戶端設定:

url=jdbc:postgresql://:26000,:26000/?connectTimeout=5&targetServerType=master&tcpKeepAlive=true

我比較偏好這種采用主機清單的方式,通過配置用戶端參數,能夠實作自動主庫發現,負載均衡,隻讀從庫等各類應用場景需求。這種方式也避免了VIP,DNS在不同架構下的管理複雜性,相對更通用一些。是以我在openGauss的整個企業級部署裡面,充分利用jdbc驅動的檢測能力,将多IP清單的配置作為标準設定,期望openGauss主從切換的情況下,用戶端資料源能自動連接配接到正确的節點。

資料源連接配接池測試

最常見的資料庫通路方式是通過在中間件裡定義連接配接資料庫的資料源連接配接池,維持一定的長連結供應用通路,減少每次通路資料庫需要建立連接配接的開銷。

tomcat使用druid資料源配置

例如tomcat采用druid資料源連接配接資料庫,設定如下:

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

為了保障資料源裡連接配接的可用性,需要對空閑資料源進行周期性檢測。參數testWhileIdle設定為true,validationQuery設定為"select 1",validationQueryTimeout設定為5秒。預期連接配接池裡的連接配接在被使用前會通過validationQuery檢測是否可用。

測試中遇到的問題

在一系列的資料源連接配接池和資料庫的高可用測試中,遇到了一個奇怪的現象。當openGauss的主庫(197.0.34.50)掉電後,備庫(197.0.34.51)切換為新的主庫(HA軟體自動切換,測試中也可以人工操作切換),但是tomcat的連接配接一直沒有連接配接到新的主庫(197.0.34.51)上來。檢視用戶端上的連接配接長時間處于ESTABLISHED的狀态,看起來不觸發TCP_KEEPALIVE的機制是不會斷掉的。而應用的通路全部都停滞了。

連接配接池檢測機制分析

從這個問題的現象來看,顯然validationQueryTimeout沒有生效。抓取druid的運作trace發現時間不對:

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

isValidConnection中檢測語句傳回時間是931454.501349ms,遠遠超過5秒。進一步分析源碼發現,druid的檢測代碼有下面的内容,是通過将資料源配置參數validationQueryTimeout轉化為postgresql裡的setQueryTimeout參數。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

顯然druid并沒有設定自己的定時器來判斷validationQuery是否逾時,而是交給了openGauss的jdbc驅動。

openGauss jdbc相關源碼解析

現在要做的事情就是分析openGauss驅動代碼裡面的setQueryTimeout為什麼沒有生效。為了驗證這個問題,我單獨改寫了份驗證的程式。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

程式啟動後,觀察連接配接的狀态。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

這個時候直接給主機關機,用戶端看連接配接還是ESTABLISHED的狀态。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

java程式一直hang,等待sql傳回。二十分鐘後報錯:

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

報錯内容是連接配接逾時,而且時間也遠遠超過setQueryTimeout設定的20秒。分析代碼發現源代碼QueryExecutorBase.java裡的sendQueryCancel函數抓到異常并不處理傳回。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

而調用者源碼PgConnection.java中 cancelQuery() 也僅僅是發起了sendQueryCancel就結束了,有沒處理可能出現的異常。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

openGauss jdbc源碼改進送出

現在解題思路就比較簡單了,首先讓sendQueryCancel能夠傳回異常,然後由cancelQuery函數catch這個異常并做處理,也就是關閉這個queryExecutor。我在被調用者sendQueryCancel中抛出逾時異常,然後在調用者cancelQuery中抓取這個異常并關閉queryExecutor就可以了。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

重新編譯顯得jar包後,測試下版本的驅動,在同樣的情況下,錯誤變成了Socket closed。

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

trace日志裡能看到新的代碼成功執行了:

openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階
openGauss 資料庫 JDBC 用戶端配置探索與改進 | 運維進階

從測試結果來看滿足需求,在連接配接池情況下進一步驗證也能切換了。目前我已經将這段代碼修改送出到了社群,合并在master版本裡面。

openGauss資料庫連接配接總結

在資料庫連接配接url裡面,多個IP是順序連接配接的,如果第一個ip不通,那麼連接配接需要等待connectTimeout參數控制逾時時間,才會連接配接下一個ip。這也是在配置過程裡需要關注的點。最後總結下多ip主機清單的設定:

1.合理設定資料源連接配接池的大小。主要是initialSize,minIdle和maxActive這幾個參數。建議不要設定過大的連接配接池。在生産中其實很少有活動會話很高的系統,但是确常見幾千幾萬的空閑連接配接在資料庫上。這些都是資源浪費,沒有意義。

2.通過建立不同的資料源來實作讀寫分離和負載均衡。openGauss是單機資料庫,利用好從庫能夠實作隻讀性能擴充,減少主庫壓力。

3.利用驅動能力實作高可用自動切換。這種方式也适合跨區域跨網段等VIP不能漂移的場景。

繼續閱讀