[英]Evicting connections to a read-only node in a cluster from the connection pool
我的應用程序連接到兩個MySQL 5.6(實際上是Amazon Aurora )實例的故障轉移群集。 活動節點始終可寫入,而被動節點以read_only
模式運行(這與規范的MySQL故障轉移群集不同,默認情況下,所有從屬節點都可寫入。 Amazon RDS提供符號DNS名稱,該名稱始終指向活動MySQL節點的IP地址。
在故障轉移過程中,前一個主設備以read_only
模式重新啟動,而前一個被動節點變為可寫入,並被提升為主設備。 此外,DNS記錄也會更改,因此群集的DNS名稱現在指向新的主節點。
即使我完全禁用Java端的DNS緩存(通過sun.net.inetaddr.ttl
或networkaddress.cache.ttl
),特定於操作系統的DNS緩存仍然有效,因此在數據庫故障轉移后我最終得到了我的DBCP池充滿了與只讀MySQL實例的連接。 這些連接是valid
,即它們是在故障轉移完成之后但在 DNS緩存過期之前獲得的。 另外,這些連接都沒有設置readOnly
標志,所以我無法判斷我是否正在與一個只讀實例進行通信,直到我執行一些DML,這就是當ER_OPTION_PREVENTS_STATEMENT
榮耀時。 即使我通過調用setReadOnly(false)
顯式地將連接置於讀寫模式並設置readOnlyPropagatesToServer
標志,這只會導致驅動程序向服務器發送SET SESSION TRANSACTION READ WRITE
,這不會導致拋出任何異常。
我希望盡可能少地影響應用程序邏輯來解決這個問題。 如果有一種方法可以將只讀實例的連接視為無效/封閉連接(即從池中驅逐它),則可以實現這一點。
我可以使用一個驗證查詢,例如SHOW GLOBAL VARIABLES LIKE 'read_only'
,並附加一個額外的邏輯嗎? 是否可以根據驗證查詢返回的標量值來影響池的行為?
可以使用以下驗證查詢:
select case when @@read_only = 0 then 1 else (select table_name from information_schema.tables) end as `1`
如果數據庫以只讀模式運行,則查詢將失敗
ERROR 1242 (21000): Subquery returns more than 1 row
由於Amazon Aurora在集群中的讀取器端點上設置innodb_read_only
但不設置read_only
,因此驗證查詢可以重寫為
select case when @@read_only + @@innodb_read_only = 0 then 1 else (select table_name from information_schema.tables) end as `1`
靈感來自這個答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.