XA事務的隔離級別算什麼級別?

按照個人理解,xa事務第二階段commit由於涉及多個節點,提交會有先後順序不可能同一個時間點執行,所以無法避免臟讀,隔離級別只能算讀未提交。

以mysql為例,官方文檔:However, for a distributed transaction, you must use the SERIALIZABLE isolation level to achieve ACID properties. It is enough to use REPEATABLE READ for a nondistributed transaction, but not for a distributed transaction

問題來了

1.mysql的xa事務為什麼要求SERIALIZABLE 隔離,單個mysql的SERIALIZABLE 並不能避免上面提到的臟讀,那mysql這麼寫是什麼個原理。

2.分散式事務如果要想實現讀已提交或以上的隔離級別,有什麼好的辦法?個人想法加全局鎖是可以實現,還有更好方法沒


同意上面的觀點: serializable 隔離級別下, XA 事務是能夠避免臟讀的。

仔細想一下就能明白:XA 事務由於不同節點 commit 的先後順序,導致有些節點上的已提交數據在 XA 事務 「真正」 完成 commit 前會被其他事務讀到。 但是,XA 只要保證這些這些 「提前讀到數據」 的事務,在訪問其他節點時,也讀到相同的已提交數據就 OK。

換句話說,就是 XA 事務修改了節點 A 上的數據 a --&> a", 節點 B 上的數據 b --&> b",在提交階段,可能 a" 被其他事務讀到,這時候只要保證讀到 a" 的事務也同時讀到 b" ,就是一致的。反過來,如果其他事務讀到的是 a", b 或者 a, b", 就違反了一致性,產生了臟讀。

想通了這點,就能明白 mysql 為什麼要求 XA 事務跑在 serializable 隔離級別了:因為 serializable 級別下 mysql 會對所有 讀加鎖。還是上面的例子,如果 XA 事務中在節點 A commit 之後,有事務讀到了 a",那麼這個事務在讀節點 B 時一定會阻塞,不可能讀到數據 b。

反之,如果有事務提前讀到了 a, 那麼其他事務一定會在寫入 a --&> a" 時阻塞,保證當前事務只會讀到 b。不會出現中間事務修改了 a --&> a", b --&> b" 再 commit,結果讓當前事務讀到 b" 的情況。

至於有中間事務執行了 b --&> b"", 讓當前事務讀到 a, b"" 的情況 —— 由於中間事務從來沒有訪問過 a, 從 serializable 的角度我們完全可以認為這個中間事務發生於當前事務之前嘛,不違反一致性。

至於問題 2,分散式事務有沒有辦法實現 Repeatable-Read 以上的隔離級別,結論當然是可以,而且不需要依賴 XA 這種粗糙的加鎖方式。工作相關,就不在這裡回答了。


這是一個很有趣的問題,值得討論。我理解,這裡XA要求下層使用serializable隔離級別,等價於讀加長謂詞鎖和長寫鎖,所有讀寫都這麼做且是兩階段鎖,是能避免臟讀的。而且,這樣得到的XA事務也是serializable的。因為這裡XA事務沒有中心節點推進事務版本或者true time,似乎想不到提供repeatable read而非serializable的其他方法。


問題一 用SERIALIZABLE做分散式事務是可以避免臟讀的,SERIALIZABLE事務針對讀操作也是加鎖的,這樣整個分散式事務符合兩階段鎖協議2pl,而2pl本事理論已經證明符合SERIALIZABLE,肯定可以避免臟讀。

問題二 很多資料庫都實現了分散式的讀已提交,mvcc用一個集中式或者邏輯上單調遞增的東西分配snapshot就行,每一個statement去取一個snapshot就行。

比如percolator用timestamp oracle生成snapshot。 spanner用truetime生成snapshot,pg-xc用gtm生成snapshot,cockroach使用hlc來生成時間戳。

以上供參考。


問題1.MySQL中SERIALIZABLE級別讀操作加讀鎖、寫操作加寫鎖,REPEATABLE READ級別讀操作不加鎖,採用多版本讀,寫操作加寫鎖。在MySQL的XA事務中,由於REPEATABLE READ的多版本讀是本地多版本不是全局多版本,會導致讀取不一致的數據,也就是臟讀。

下面給出REPEATABLE READ級別的一個操作案例

T1從A賬戶轉X元轉到B賬戶,A,B賬戶分別在兩個節點。T2讀取A與B賬戶的總額。

在t6時刻,T2讀取的賬戶總額是A+X+B,是臟數據。

如果採用SERIALIZABLE,讀寫均加鎖,可以避免上面的結果。

問題2.MySQL中XA採用SERIALIZABLE級別,全局事務可以達到SERIALIZABLE的級別。但是大量的讀鎖會耗費很多資源,同時在讀寫並發時,會帶來更多的等待時間。這也是為什麼採用mvcc多版本的原因。PG社區中,有PGXC和PGXL的方案,採用的並發機制是全局mvcc+本地寫鎖。PGXC是維持了全局活躍事務列表,從而提供全局mvcc。在上面的案例中,在t6時刻,由於全局事務沒有結束,T2從節點1讀到A,從節點2讀到B,總額是A+B。

社區版PGXC和PGXL穩定性很差,我所在團隊已經在PGXC上做了3年定製與優化工作,產品已經應用在商業生產環境。


我覺得第一個問題,讀提交(Read committed),我也不是很懂XA,事務,這些的,XA在預提交階段,數據並不會入庫,但會寫入到XA日誌文件中(5.6以支持),得到響應之後才會正式入庫,只要是寫入了XA日誌文件,就算在正式入庫時連接錯誤,也可以在次提交入庫,所以說是不會出現(臟讀)


之所以要隔離是要考慮事務的重新提交與回滾機制
否則 如果不控制順序 當時的事務快照很難做 即便做了 多個事務之間的數據控制因為涉及多個庫 很難保證數據不會互相覆蓋或者數據是想要的,排隊至少解決了部分問題

另外如果不用資料庫的機制,用分散式鎖這種又會帶來性能問題,所以隔離的代價還是比較大,

阿里的drds好像是對事物做排到 從最終一致性上做處理


推薦閱讀:

微服務如何處理分散式事務?
TiKV為什麼用一個單點的授時服務而不是用一致性集群來授時呢?
三階段提交協議如何避免協調者狀態未知的情況?
常用的分散式事務解決方案介紹有多少種?
如何理解阿里大神程立的分散式事務文檔?

TAG:一致性 | 分散式事務 | 分散式資料庫 |