深入剖析分散式事務一致性

葉東富發表於2021-12-13

概述

分散式事務是用來解決跨資料庫、跨服務更新資料一致性問題的。那麼這裡的一致性指的是什麼,什麼是強一致性,什麼是弱一致性,與CAP理論中的一致性概念是一樣的嗎?本文將為您深入解答相關的問題。

一致性指什麼

在資料庫的理論中,事務具備大家都熟悉的ACID特性,分別如下:

  • Atomicity(原子性):一個事務中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被恢復到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
  • Consistency(一致性):在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞。完整性包括外來鍵約束、應用定義的等約束不會被破壞。
  • Isolation(隔離性):資料庫允許多個併發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致資料的不一致。
  • Durability(永續性):事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失。

對於這裡面的C(一致性),我們以一個非常具體的業務例子,來進行解釋。假如我們正在處理一個轉賬業務,假設是A轉給B 30元,在本地事務的支援下,我們的使用者看到A+B的總金額,在整個轉賬前後,以及轉賬過程中,都是保持不變的。那麼這個時候使用者認為他看到的資料是一致的,符合業務約束的。

當我們業務變複雜,引入多個資料庫和大量微服務時,上述本地事務的一致性,依舊是業務非常關心。假如一個業務更新操作,跨庫或者跨服務時,那麼此時業務關心的一致性問題,就變成了 分散式事務中的一致性問題。

在單機本地事務中,A+B的總金額在任何時刻去查(以常見的ReadCommitted或ReadRepeatable隔離級別),都是不變的,也就是業務約束一直都保持的這種一致性,我們稱之為強一致性。

無法做到強一致

目前在跨庫、跨服務的分散式實際應用中,尚未看到有強一致性的方案。

我們來看看一致性級別最高的XA事務,是否是強一致的,我們以跨行轉賬(在這裡,我們以跨庫更新AB來模擬)作為例子來說明,下面是一個XA事務的時序圖:
image.png

在這個時序圖中,我們在如圖所示的時間點發起查詢,那麼我們查到的資料,將是A+B+30,不等於A+B,不符合強一致的要求。

理論上的強一致性

我們接下來思考,普通XA事務不是強一致的,但假如完全不考慮效能因素,有沒有可能在理論上做到強一致:

我們先看看如果我們把XA事務涉及的資料庫,隔離級別設定到Serializable,是否能到到強一致的效果呢?我們來看看前面的時序場景:
image.png

這種情況下,查到結果等於A+B,但是又有另一些場景出現了問題,如下圖所示:
image.png

按照圖中時序查詢的結果是:A+B-30,依舊是不一致。

深入思考這個強一致的問題之後,有一種做法可以做到強一致,做法如下:

  • 對於查詢,也採用XA事務,並且查詢資料時,採用select for update的方式,所有資料查完之後,再xa commit
  • 為了避免死鎖,需要將涉及到的資料庫排序,訪問資料都必須要按照相同的資料庫順序來寫入和查詢

在上述策略下,我們可以看到,在時序圖任何一個時間點進行查詢,獲得的結果都是A+B
image.png

  • 在T0時間查詢,那麼修改一定發生在查詢全部完成之後,所以查詢得到結果A+B
  • 在T1,T2,T3查詢,那麼查詢結果返回一定全部發生在修改完成之後,所以查詢得到結果也是A+B

很明顯這種理論上的強一致,效率極低,所有有資料交集的資料庫事務都是序列執行,而且還需要按照特定的順序查詢/修改資料,因此成本極高,幾乎無法應用在生產中。

NewSQL的強一致性

我們討論了跨庫、跨微服務的分散式事務是無法做到強一致的,其實還有一種分散式資料內部的事務,因為事務跨節點了,也被成為分散式事務。這種分散式事務是可以做到強一致的,這種強一致是通過MVCC的技術達到的,原理和單機的資料庫類似,但複雜很多。詳細的實現方法可以參考谷歌的percolator

未來有沒有可能借鑑NewSQL的這種方式,來實現跨庫、跨微服務這類分散式事務的強一致性?理論上是可以的。

  • 實現跨服務但不跨庫的分散式事務一致性,會相對簡單一些,其中一種方式就是實現XA事務中的TMRESUME選項(因為最終只有一個xa commit,不會出現兩個xa commit中間的不一致時間視窗)。
  • 實現跨資料庫的分散式事務一致性,會困難很多,因為各個資料庫的內部版本機制都不一樣,想要協同非常困難。

弱一致性的分類

既然現有的各種分散式事務方案都無法做到強一致,那麼弱一致性之間是否有差別呢?我們進行了以下關於一致性強弱的分類:

一致性由強到弱分別是:

XA事務>訊息>TCC>SAGA

這裡的訊息指的是本地訊息表這種型別的分散式事務,關於這四種分散式事務的介紹,參見分散式事務最經典的七種解決方案

他們的分類為:
image.png

  • 無中間態:資料只有兩個狀態,事務前和事務後,沒有其他第三種狀態。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一樣,一致性其實高於XA。

CAP理論中的一致性

我們這裡討論的一致性是指資料庫中的一致性概念,與CAP中的一致性不同。

  • CAP中的強一致性是指使用者在分散式系統中寫完之後,立刻去讀,如果能夠像本地讀寫那樣,讀到最新版本,那麼是強一致性。
  • 分散式事務中的強一致性,是指事務進行的過程中,使用者讀取的資料始終滿足業務約束,目前在實際應用中的方案,都無法做到強一致。

上述兩者的強一致性在具體的含義上是不同的,但從使用者的視角看,也有共通性,即能否像單機系統一樣,不需要關心分散式帶來的新問題。

讀者通常會有另一個疑問,那就是分散式事務是一個分散式系統,那麼在CAP中的一致性如何?

當前Paxos/Raft等分散式共識協議已經在工業領域有了成熟的實現,當遇見機器故障或網路隔離的情況時,可以做到大約幾百個毫秒到幾秒內選舉出新的leader,從故障中恢復。也就是說CAP中,選擇CP,在A上面只有大約幾百個毫秒的不可用時間。

因此對於NewSQL或者分散式事務這類資料敏感性應用,一般都選擇CAP中的CP,而犧牲幾百毫秒的A。因此在這方面,分散式事務是CAP中強一致的。例如我們的dtm分散式事務框架,將全域性事務進度儲存在CP的資料庫中(雲廠商大多提供了CP的資料庫)

總結

本文詳盡的分析了分散式事務中一致性相關的問題,在確認沒有強一致性方案的情況下,分析了弱一致性分類及理論上可能的強一致方案。

本文許多內容屬於首創,如有考慮不周的地方,歡迎讀者在評論區一起探討。

  • 我們的公號:分散式事務
  • 我們的專案:https://github.com/yedf/dtm
  • 歡迎使用dtm,或者通過dtm學習實踐分散式事務相關知識,歡迎star支援我們

相關文章