alwaysOn為什麼不支援分布式事務

2021-09-22 23:15:09 字數 2055 閱讀 2573

alwayson是微軟從sql2012開始引入的一種高可用和高效能架構,它既可以實現故障轉移,同時又能實現查詢分離,是當前sql server的所有架構中最優秀的一種。

因此,一般我們都會推薦使用alwayson來部署生產資料庫,不過,儘管alwayson的優勢非常明顯,但並非適應於所有的業務場景。

分布式事務是指通過分布式事務協調器(msdtc)的統一控制、將事務中的每個操作分解到多台主機上分別執行、每台主機執行成功後整個事務才能提交的事務,分布式事務協調器用來保證資料的一致性。跨資料庫事務與此類似,只是不會用到msdtc,而是將dbid最小的乙個作為

分布式事務協調器。

如果在乙個分布式事務執行期間alwayson發生了故障轉移,ag服務從主副本轉移到了輔助副本,分布式事務協調器因為收不到原主副本的事務提交確認資訊,認為事務執行失敗,然後將其他參與(分布式事務的)節點上的應要提交的事務回滾。對於新的主副本,因為沒有參與之前的分布式事務,因此無法從分布式事務協調器獲取事務的狀態,繼續維持現有的資料不變化,從而導致新副本與參與分布式事務的其他節點上的資料不一致。

備註:跨資料庫事務的原因與此類似。

下面我們通過圖例來展示這個過程:

下圖:假設有abc三個節點,ac之間做了alwayson,其中a.table1中a的初始值為0,b.table1中a的初始值為1000。有乙個分布式事務1,需要將節點a的表中a加上1000,同時需要在節點b的表中a減去1000。 1

2

3

4

5

6

7

begintran

updatea.table1seta=a+1000 ;

updateb.table1seta=a-1000 ;

committran

正常情況下,最後的結果應該是a.table1.a=1000,b.table1.a=0,,c.table1.a=1000。

現在有這樣乙個場景,a和b都已經commit,a.table1.a=1000,b.table1.a=0,且a已經將事務1的操作通過日誌同步到了主機c,c.table1.a=1000。

正常情況下,主機a和b都向事務協調器傳送commit ack(提交確認)資訊,事務協調器收到兩者的確認資訊後就可以將整個事務標記為提交。但現在a在傳送commit ack資訊時發生了宕機,分布式事務協調器只收到了主機b的commit ack,於是協調器將整個事務標記為失敗,然後在主機b上回滾事務1的操作,此時b.table1.a=1000。

節點c雖然接管了alwayson集群,因為它並不是分布式事務的執行者之一,所以它無法從分布式事務協調器獲取事務1的狀態,因此它不會回滾,a的值保持不變。最後c.table1.a=1000、b.table1.a=1000,發生了資料不一致的問題。

參考文章:

從上文可以看到,alwayson不支援分布式事務(和跨資料庫事務)的根本原因在於主副本故障轉移到輔助副本時會造成分布式事務執行不一致。

解決這個問題的焦點就是主副本和輔助副本的故障轉移。如果主副本與輔助副本之間不允許故障轉移(也就是處於非同步同步模式下),輔助副本的職責只是接受來自主副本的日誌,然後執行redo實現同步,這樣一來就不會產生異常資料。

不過,主、輔副本無法故障轉移後,主副本存在單點故障的風險,為了避免此類情況發生,我們可以為主副本建立傳統的sql server故障轉移集群。在這種架構下,如果主節點在執行分布式事務發生了故障轉移,輔節點接管的sql例項是原主節點的同乙個例項,而且資料檔案和日誌檔案是相同的,所以不會與其他參與分布式事務的節點產生資料不一致的問題。

為什麼模板不支援分離編譯?

在c 中,為了乙個專案的規範化我們通常把 歸類為三類 宣告檔案 實現檔案 測試檔案。比如,我們要實現乙個順序表,那麼規範化就是建立3個檔案 seqlist.h 順序表相關宣告 seqlist.cpp 順序表相關實現 test.cpp 順序表測試檔案 那麼普通順序表這樣寫一點問題都沒有,用模板實現成這...

為什麼模板不支援分離編譯

在c 中,為了乙個專案的規範,我們通常把 歸為三類 宣告檔案 實現檔案 測試檔案.比如,我要用c 實現乙個鍊錶,那麼就會建立這3個檔案 linklist.h 鍊錶的相關宣告 linklist.cpp 鍊錶的實現 test.cpp 鍊錶測試 本文忽略 那麼問題來了,普通鍊錶這樣寫起來一點問題都沒有 如...

為什麼模板不支援分離編譯

在c 中,為了乙個專案的規範,我們為您通常把 歸為三類 1 宣告檔案 2 實現檔案 3 測試檔案 比如我們要用c 實現乙個鍊錶,那麼我們就會建立這3個檔案 linklist.h 鍊錶的相關宣告 lisklist.cpp 鍊錶的實現 test.cpp 鍊錶測試 如果一旦,我們要通過類模板來實現鍊錶 仍...