深入剖析分佈式事務一致性
概述
分佈式事務是用來解決跨數據庫、跨服務更新數據一致性問題的。那麼這裏的一致性指的是什麼,什麼是強一致性,什麼是弱一致性,與 CAP 理論中的一致性概念是一樣的嗎?本文將爲您深入解答相關的問題。
一致性指什麼
在數據庫的理論中,事務具備大家都熟悉的 ACID 特性,分別如下:
-
Atomicity(原子性):一個事務中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被恢復到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
-
Consistency(一致性):在事務開始之前和事務結束以後,數據庫的完整性沒有被破壞。完整性包括外鍵約束、應用定義的等約束不會被破壞。
-
Isolation(隔離性):數據庫允許多個併發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致數據的不一致。
-
Durability(持久性):事務處理結束後,對數據的修改就是永久的,即便系統故障也不會丟失。
對於這裏面的 C(一致性),我們以一個非常具體的業務例子,來進行解釋。假如我們正在處理一個轉賬業務,假設是 A 轉給 B 30 元,在本地事務的支持下,我們的用戶看到 A+B 的總金額,在整個轉賬前後,以及轉賬過程中,都是保持不變的。那麼這個時候用戶認爲他看到的數據是一致的,符合業務約束的。
當我們業務變複雜,引入多個數據庫和大量微服務時,上述本地事務的一致性,依舊是業務非常關心的。假如一個業務更新操作,跨庫或者跨服務時,那麼此時業務關心的一致性問題,就變成了分佈式事務中的一致性問題。
在單機本地事務中,A+B 的總金額在任何時刻去查(以常見的 ReadCommitted 或 ReadRepeatable 隔離級別),都是不變的,也就是業務約束一直都保持的這種一致性,我們稱之爲強一致性。
無法做到強一致
目前在跨庫、跨服務的分佈式實際應用中,尚未看到有強一致性的方案。
我們來看看一致性級別最高的 XA 事務,是否是強一致的,我們以跨行轉賬(在這裏,我們以跨庫更新 AB 來模擬)作爲例子來說明,下面是一個 XA 事務的時序圖:
在這個時序圖中,我們在如圖所示的時間點發起查詢,那麼我們查到的數據,將是 A+B+30,不等於 A+B,不符合強一致的要求。
理論上的強一致性
我們接下來思考,普通 XA 事務不是強一致的,但假如完全不考慮性能因素,有沒有可能在理論上做到強一致:
我們先看看如果我們把 XA 事務涉及的數據庫,隔離級別設定到 Serializable,是否能到到強一致的效果呢?我們來看看前面的時序場景:
這種情況下,查到結果等於 A+B,但是又有另一些場景出現了問題,如下圖所示:
按照圖中時序查詢的結果是:A+B-30,依舊是不一致。
深入思考這個強一致的問題之後,有一種做法可以做到強一致,做法如下:
-
對於查詢,也採用 XA 事務,並且查詢數據時,採用 select for update 的方式,所有數據查完之後,再 xa commit
-
爲了避免死鎖,需要將涉及到的數據庫排序,訪問數據都必須要按照相同的數據庫順序來寫入和查詢
在上述策略下,我們可以看到,在時序圖任何一個時間點進行查詢,獲得的結果都是 A+B
-
在 T0 時間查詢,那麼修改一定發生在查詢全部完成之後,所以查詢得到結果 A+B
-
在 T1,T2,T3 查詢,那麼查詢結果返回一定全部發生在修改完成之後,所以查詢得到結果也是 A+B
很明顯這種理論上的強一致,效率極低,所有有數據交集的數據庫事務都是串行執行,而且還需要按照特定的順序查詢 / 修改數據,因此成本極高,幾乎無法應用在生產中。
NewSQL 的強一致性
我們討論了跨庫、跨微服務的分佈式事務是無法做到強一致的,其實還有一種分佈式數據內部的事務,因爲事務跨節點了,也被成爲分佈式事務。這種分佈式事務是可以做到強一致的,這種強一致是通過 MVCC 的技術達到的,原理和單機的數據庫類似,但複雜很多。詳細的實現方法可以參考谷歌的 percolator
未來有沒有可能借鑑 NewSQL 的這種方式,來實現跨庫、跨微服務這類分佈式事務的強一致性?理論上是可以的。
-
實現跨服務但不跨庫的分佈式事務一致性,會相對簡單一些,其中一種方式就是實現 XA 事務中的 TMRESUME 選項(因爲最終只有一個 xa commit,不會出現兩個 xa commit 中間的不一致時間窗口)。
-
實現跨數據庫的分佈式事務一致性,會困難很多,因爲各個數據庫的內部版本機制都不一樣,想要協同非常困難。
弱一致性的分類
既然現有的各種分佈式事務方案都無法做到強一致,那麼弱一致性之間是否有差別呢?我們進行了以下關於一致性強弱的分類:
一致性由強到弱分別是:
XA 事務 > 消息 > TCC>SAGA
這裏的消息指的是本地消息表這種類型的分佈式事務,關於這四種分佈式事務的介紹,參見分佈式事務最經典的七種解決方案
他們的分類爲:
-
無中間態:數據只有兩個狀態,事務前和事務後,沒有其他第三種狀態。XA、消息這兩種都是這種
-
有中間態:數據有中間態,例如 TCC 的 Try,數據狀態和事務前事務後都不一樣;SAGA 也有中間態,假如一個 SAGA 事務執行正向操作後數據爲 W,又回滾了,那麼 W 也與事務前事務後的狀態不同。
-
XA:XA 雖然不是強一致,但是 XA 的一致性是多種分佈式事務中,一致性最好的,因爲他處於不一致的狀態時間很短,只有一部分分支開始 commit,但還沒有全部 commit 的這個時間窗口,數據是不一致的。因爲數據庫的 commit 操作耗時,通常是 10ms 內,因此不一致的窗口期很短。
-
消息:消息型在第一個操作完成後,在所有操作完成之前,這個時間窗口是不一致的,持續時長一般比 XA 更久。
-
TCC:TCC 的中間態,通常可控,可以自定義。通常情況下,這部分數據不展示給用戶,因此一致性比後面的 SAGA 要好。
-
SAGA:SAGA 如果發生回滾,而子事務中正向操作修改的數據會被用戶看到,可能給用戶帶來較差的體驗,因此一致性是最差的。
我們這裏的分類僅僅從我們關心的幾個維度進行了歸納,適用於多數場景,但並不一定適用所有情況。在實際的應用中,也可能出現 TCC 的一致性比消息更好,例如我在 Try 中執行 xa prepare,Confirm 中執行 xa commit,Cancel 中執行 xa rollback,在這種實現下,TCC 的一致性就跟 XA 一樣,一致性其實高於消息。
CAP 理論中的一致性
我們這裏討論的一致性是指數據庫中的一致性概念,與 CAP 中的一致性不同。
-
CAP 中的強一致性是指用戶在分佈式系統中寫完之後,立刻去讀,如果能夠像本地讀寫那樣,讀到最新版本,那麼是強一致性。
-
分佈式事務中的強一致性,是指事務進行的過程中,用戶讀取的數據始終滿足業務約束,目前在實際應用中的方案,都無法做到強一致。
上述兩者的強一致性在具體的含義上是不同的,但從用戶的視角看,也有共通性,即能否像單機系統一樣,不需要關心分佈式帶來的新問題。
讀者通常會有另一個疑問,那就是分佈式事務是一個分佈式系統,那麼在 CAP 中的一致性如何?
當前 Paxos/Raft 等分佈式共識協議已經在工業領域有了成熟的實現,當遇見機器故障或網絡隔離的情況時,可以做到大約幾百個毫秒到幾秒內選舉出新的 leader,從故障中恢復。也就是說 CAP 中,選擇 CP,在 A 上面只有大約幾百個毫秒的不可用時間。
因此對於 NewSQL 或者分佈式事務這類數據敏感性應用,一般都選擇 CAP 中的 CP,而犧牲幾百毫秒的 A。因此在這方面,分佈式事務是 CAP 中強一致的。例如我們的 dtm 分佈式事務框架,將全局事務進度保存在 CP 的數據庫中(雲廠商大多提供了 CP 的數據庫)
總結
本文詳盡的分析了分佈式事務中一致性相關的問題,在確認沒有強一致性方案的情況下,分析了弱一致性分類及理論上可能的強一致方案。
作者:葉東富
來源:segmentfault.com/a/1190000041106277
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/BtpekTzsj82flSF1wyTcLA