接上文:https://www.cnblogs.com/wy123/p/17905118.html,關於AlwaysOn主副本與輔助副本之間提交模式與安全故障轉移的話題 參考AlwaysOn屬性面板中的信息 1,主節點非同步提交模式:如果主要副本配置為“非同步提交模式” ,則從節點不管是同步或者非同步,主 ...
接上文:https://www.cnblogs.com/wy123/p/17905118.html,關於AlwaysOn主副本與輔助副本之間提交模式與安全故障轉移的話題 參考AlwaysOn屬性面板中的信息
同步提交模式退化為非同步模式
如上截圖,將SQL1和SQL2兩個節點設置為同步模式,SQL1上執行的事務性操作,將會等待日誌傳送到SQL2節點之後再反饋給客戶端提交成功的信息,這一點沒有問題select r.replica_server_name, r.availability_mode, r.availability_mode_desc, r.failover_mode_desc, r.session_timeout, s.connected_state_desc from sys.availability_replicas r inner join sys.dm_hadr_availability_replica_states s on s.replica_id = r.replica_id
數據已同步到SQL1和SQL2兩個節點
目前SQL1和SQL2兩個節點是同步模式,現在簡單粗暴,直接關閉SQL2節點,模擬同步模式的輔助副本宕機的情況
此時會發現,SQL1節點仍舊可以正常讀寫,這就是同步模式的退化機制,就是同步模式的輔助副本,不管是同步模式(這裡SQL1和SQL2就是同步模式)或者非同步模式,都不會影響主副本的讀寫。
其實此時主副本已經處於裸奔了,因為與他同步模式的輔助副本實際上已經下線。
這種情況下,主副本和輔助副本之間所謂的“同步提交”模式實際上形同虛設,實際上完整的數據實際上只有SQL1上的一份(SQL3是一步提交模式),極端情況下如果SQL1再宕機,存在數據丟失的風險。
AlwaysOn節點中Session Timeout的作用
備註里提到的“如果某一輔助副本超過了主副本的會話超時期限,則主副本將暫時切換到該輔助副本的非同步提交模式。 在該輔助副本重新與主副本連接後,它們將恢復同步提交模式。”
如果同步提交模式在祝福本會話超時之前,主節點在寫入數據時時什麼情況?再次實驗,把SQL2節點正常啟動,恢復同步提交模式,同時修改Session Timeout為一個較大的值,這裡修改為600(預設是10秒)
此時再次關閉SQL2節點,然後在SQL1節點上寫入數據,會出現什麼情況?參考截圖,實際上這個insert語句的執行會一直等下去,直到超出上面設置的session timeout的值。
因此這裡就有一個選擇,在某些高安全的模式下,如果跟主副本同步提交的輔助副本宕機,主副本可選選擇一會等待,直到輔助副本上線
實際上這個SQL會一直執行到上面設置的Session Timeout,也就是600秒(讀操作不受影響),這裡執行到9分52秒是因為設置完這個時間,從關閉SQL2節點的MSSQL服務到SQL開始執行有幾秒鐘時間,超時時間是SQL1最早探測到SQL2下線開始計算
令筆者意外的是,在上面這個SQL執行期間,啟動SQL2上的服務,發現主副本(SQL1)上可以正常連接到SQL2,但是SQL2無法加入AG group,直至這個insert語句執行完成,SQL2才正常加入到AG Group中來。
REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT
正如這個參數名字上的含義,主副本在寫入數據時,要求同步提交到(N個)輔助副本,聯繫上面提交模式的選擇,如果節點之間本身是非同步提交模式,那麼設置同步提交到N個節點是沒有意義的,這裡嘗試將所有節點設置為非同步提交模式,同時REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT設置為1,嘗試保持會發現直接報錯:
“The Alter operation is not allowed by the current availability-group configuration. The required_synchronized_secondaries_to_commit 1 is greater than the 0 possible secondary synchronous-commit availability replicas in availability group 'ag1'. Change one of the existing asynchronous-commit replicas to the synchronous-commit availability mode, and retry the operation. (.Net SqlClient Data Provider)”
其實不難理解:既然要求同步提交打一個節點,那麼節點之間必然是同步模式,如果是非同步提交模式,就相互矛盾了。
按照正常模式,設置SQL1和SQL2之間為同步提交模式,設置REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT為1,可以正常保存。
此時AG節點正常同步數據,如果目前再次關閉SQL2節點,會發生什麼?
同樣地,SQL1上的寫操作會等待SQL2響應(SQL1上的讀操作不受影響),此時SQL2已經宕機,然後等待超時(session timeout)之後會發生什麼?
可以看到此時SQL1上並沒有像第二個case的“自動退化”為非同步模式,而是給出了一個插入失敗的錯誤提示
Remote harden of transaction 'INSERT' (ID 0x000000000000ddc6 0000:000003c4) started at Dec 18 2023 9:34PM in database 'DB01' at LSN (37:2080:3) failed. (1 row affected) Msg 596, Level 21, State 1, Line 35 Cannot continue the execution because the session is in the kill state. Msg 0, Level 20, State 0, Line 35 A severe error occurred on the current command. The results, if any, should be discarded.
此時再嘗試訪問DB01會給出一個如下錯誤提示:
Msg 988, Level 14, State 1, Line 34
Unable to access database 'DB01' because it lacks a quorum of nodes for high availability. Try the operation again later.
也就是DB01連讀操作都不允許了,參考這裡:https://learn.microsoft.com/zh-cn/sql/linux/sql-server-linux-availability-group-ha?view=sql-server-ver15
在完成故障轉移之前,主要副本拒絕所有連接。
可見,AlwaysOn節點之間,如果在忽略REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT參數的情況下,因為主副本存在一個退化為非同步的情況,
不管是同步或者非同步模式,實際上都是不完全“安全”的。只有在要求強一致(兩個或者多個節點同步提交)且設置REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT大於1的時候,主節點才能完全安全模式。