阿里妹導讀:分布式事務中涉及的參與者分布在異步網絡中,參與者通過網絡通信來達到分布式一致性,網絡通信不可避免出現失敗、超時的情況,因此分布式事務的實現比本地事務面臨更多的困難。本文歸納總結五種分布式事務解決方案,並剖析其特點。較長,同學們可收藏後再看。
文末福利:Java 程式設計師學習清單。
概述
事務是一組不可分組的操作集合,這些操作要麼都成功執行,要麼都取消執行。最典型的需要事務的場景是銀行帳戶間的轉帳:假如 A 帳戶要給 B 帳戶轉帳 100 元,那麼 A 帳戶要扣減 100 元,B 帳戶要增加 100 元,這兩個帳戶的數據變更都成功才可算作轉帳成功。更嚴格來說,可以用 ACID 四個特性表述事務:
Atomicity:原子性,事務中的所有操作要麼都成功執行,要麼都取消執行,不能存在部分執行,部分不執行的狀態。
Consistency:一致性,舉個例子簡單的理解就是,A、B 兩個帳戶各有 100 元,無論兩個帳戶並發相互轉帳多少次,兩個帳戶的資金總額依然是 200 元。
Isolation:隔離性,並發事務之間的相互影響程度,隔離性也是分級別的:讀未提交、讀已提交、可重複讀等。
Durability:持久性,事務完成後對數據的更改不會丟失。
單體資料庫不涉及網絡交互,所以在多表之間實現事務是比較簡單的,這種事務我們稱之為本地事務。
但是單體資料庫的性能達到瓶頸的時候,就需要分庫(分物理實例),就會出現跨庫(資料庫實例)的事務需求;隨著企業應用的規模越來越大,企業會進一步進行服務化改造,以滿足業務增長的需求;當前微服務架構越來越流行,跨服務的事務場景也會越來越多。
這些都是分布式事務的需求。分布式事務是指是指事務的發起者、參與者、數據資源伺服器以及事務管理器分別位於分布式系統的不同節點之上。
概括起來,分布式事務有三種場景:
跨資料庫分布式事務跨服務分布式事務混合式分布式事務
分布式事務中涉及的參與者分布在異步網絡中,參與者通過網絡通信來達到分布式一致性,網絡通信不可避免出現失敗、超時的情況,因此分布式事務的實現比本地事務面臨更多的困難。下面介紹幾種常見的分布式事務解決方案。
分布式事務模式
XA Specification
最早的分布式事務產品可能是 AT&T 在 20 世紀 80 年代推出的 Tuxedo (Transactions for Unix, Extended for Distributed Operations),Tuxedo 最早是為了電信領域的 OLTP 系統研發的分布式事務中間件,後來標準化組織 X/Open 吸收採納了 Tuxedo 的設計思想和一些接口,推出了分布式事務規範:XA Specification。
XA 規範中定義了分布式事務處理模型,這個模型中包含四個核心角色:
RM (Resource Managers):資源管理器,提供數據資源的操作、管理接口,保證數據的一致性和完整性。最有代表性的就是資料庫管理系統,當然有的文件系統、MQ 系統也可以看作 RM。
TM (Transaction Managers):事務管理器,是一個協調者的角色,協調跨庫事務關聯的所有 RM 的行為。
AP (Application Program):應用程式,按照業務規則調用 RM 接口來完成對業務模型數據的變更,當數據的變更涉及多個 RM 且要保證事務時,AP 就會通過 TM 來定義事務的邊界,TM 負責協調參與事務的各個 RM 一同完成一個全局事務。
CRMs (Communication Resource Managers):主要用來進行跨服務的事務的傳播。
下圖是 XA 規範中定義的事務模型圖,其中:發起分布式事務的 TM 實例稱之為 root 節點,其他的 TM 實例可以統稱為事務的參與者。事務發起者負責開啟整個全局事務,事務參與者各自負責執行自己的事務分支。如果TM實例發起了對其他 TM 實例的服務調用,那麼發起者就被成為 Superior,被調用這就被稱之為 Subordinate 節點。
圖源:《Distributed Transaction Processing:Reference Model, Version 3》 Page 32,Figure 3-2
XA 規範中分布式事務是構建在 RM 本地事務(此時本地事務被看作分支事務)的基礎上的,TM 負責協調這些分支事務要麼都成功提交、要麼都回滾。XA 規範把分布式事務處理過程劃分為兩個階段,所以又叫兩階段提交協議(two phrase commit):
1)預備階段
TM 記錄事務開始日誌,並詢問各個 RM 是否可以執行提交準備操作。
RM 收到指令後,評估自己的狀態,嘗試執行本地事務的預備操作:預留資源,為資源加鎖、執行操作等,但是並不提交事務,並等待 TM 的後續指令。如果嘗試失敗則告知 TM 本階段執行失敗並且回滾自己的操作,然後不再參與本次事務(以 MySQL 為例,這個階段會完成資源的加鎖,redo log 和 undo log 的寫入)。
TM 收集 RM 的響應,記錄事務準備完成日誌。
2)提交/回滾階段
這個階段根據上個階段的協調結果發起事務的提交或者回滾操作。
如果所有 RM 在上一個步驟都返回執行成功,那麼:
TM 記錄事務 commit 日誌,並向所有 RM 發起事務提交指令。
RM 收到指令後,提交事務,釋放資源,並向 TM 響應「提交完成」。
如果 TM 收到所有 RM 的響應,則記錄事務結束日誌。
如果有 RM 在上一個步驟中返回執行失敗或者超時沒有應答,則 TM 按照執行失敗處理,那麼:
記錄事務 abort 日誌,向所有 RM 發送事務回滾指令。
RM 收到指令後,回滾事務,釋放資源,並向 TM 響應回滾完成。
如果 TM 收到所有 RM 的響應,則記錄事務結束日誌。
針對部分場景,XA 規範還定義了如下優化措施:
如果 TM 發現整個事務只涉及到一個 RM,那麼就會將整個過程退化為一階段提交。
如果 RM 收到的 AP 的數據操作是只讀操作,那麼它可以在階段 1 就將事務完成並告知 TM 其不再參與階段 2 的過程。會有髒讀的風險。
如果 RM 在階段1完成後,長時間等不到階段 2 的指令,那麼其可以自動提交或者回滾本地事務。這叫做 Heuristic Completion,注意這種場景有可能會破壞事務的一致性,產生異常。
XA 規範中詳細定義了各個核心組件之間的交互接口,以 TM 和 RM 的交互接口為例,如下圖,一次完整的全局事務,TM 和 RM 之間的交互還是比較頻繁的:
事務的執行過程中,宕機和網絡超時都有可能發生,針對這些異常場景,不同 XA 規範的實現,對異常處理做法可能不同,可參考如下:
TM 在階段 1 中詢問 RM 前宕機,恢復後無需做任何操作。
TM 在階段 1 中詢問 RM 後宕機,可能只有部分 RM 收到了階段 1 的請求,因此此時需要向 RM 發起回滾請求。
TM 在階段 1 中詢問 RM 完畢,但是在就準備完成日誌時宕機,因不清楚宕機前的事務協商的結果,因此恢復後需要向 RM 發起回滾請求。
TM 在階段 1 中記錄完畢事務準備完成日誌後宕機,恢復後可以根據日誌發起提交或者回滾的指令。
TM 在階段 2 中記錄 commit/abort 日誌前宕機,恢復後可以根據日誌發起提交或者回滾指令。
TM 在階段 2 中記錄事務結束日誌前宕機,恢復後可以根據日誌發起提交或者回滾指令。
TM 在階段 2 中記錄事務結束日誌後宕機,恢復後無需做任何操作。
階段 1 中,RM 有超時情況時,TM 按失敗處理,給所有 RM 發送回滾指令。
階段 2 中,RM 有超時情況是,TM 需要對超時的 RM 持續重複發送指令。
特點剖析
XA 兩階段提交協議設計上是要像本地事務一樣實現事務的 ACID 四個特性:
原子性:在 prepare 和 commit 階段保證事務是原子性的。
一致性:XA 協議實現的是強一致性。
隔離性:XA 事務在完成之前一直持有資源的鎖,所以可以做到寫隔離。
持久性:基於本地事務實現,所以這一點沒有問題。
XA 是出現最早的分布式事務規範,主流資料庫 Oracle、MySQL、SQLServer 等都支持 XA 規範,J2EE 中的 JTA 規範也是參照 XA 規範編寫的,與 XA 規範兼容。
XA 是在資源管理層面實現的分布式事務模型,對業務的入侵度較低。
XA 兩階段提交協議可以覆蓋分布式事務的三種場景,但是全局事務的執行過程中,RM 一直持有資源的鎖,如果參與的 RM 過多,尤其是跨服務的場景下,網絡通信的次數和時間會急劇變多,所以阻塞的時間更長,系統的吞吐能力變得很差,事務死鎖出現的概率也會變大,所以並不適合微服務架構場景中的跨服務的分布式事務模式。
每一個 TM 域來說,由於 TM 是單點,存在單點故障風險,如果 TM 在階段1之後掛掉,會導致參與的 RM 長時間收不到階段 2 的請求而長期持有資源的鎖,影響業務的吞吐能力。同時一次完整的全局事務,TM 和 RM 之間的交互多達 8 次,太繁瑣,非常影響系統的處理性能。
XA 兩階段協議可能會造成腦裂的異常,假如 TM 在階段 2 通知 RM 提交事務時,如果指令發出後就宕機了,而只有部分 RM 收到了提交請求,那麼當 TM 恢復的時候,就無法協調本次事務所有的 RM 本地事務的一致性了。
XA 要處理的異常場景非常多,對框架的實現有一定的挑戰,開源的實現,可以參考:Atomikos,Bitronix。
針對 XA 兩階段提交中的問題,有人提出了三階段提交的改進方案,三階段提交方案主要解決了單點故障問題,並在 RM 側也引入了超時機制,以避免資源的長時間鎖定。但是三階段提交方案依然無法避免腦裂的異常情況出現,實際應用案例很少,感興趣的同學可以自行找相關資料了解。
TCC
TCC (Try、Commit、Cancel) 是一種補償型事務,該模型要求應用的每個服務提供 try、confirm、cancel 三個接口,它的核心思想是通過對資源的預留(提供中間態),儘早釋放對資源的加鎖,如果事務可以提交,則完成對預留資源的確認,如果事務要回滾,則釋放預留的資源。
TCC 也是一種兩階段提交協議,可以看作 2PC/XA 的一種變種,但是不會長時間持有資源鎖。
TCC 模型將事務的提交劃分為兩個階段:
1)階段 1
完成業務檢查(一致性)、預留業務資源(準隔離性),即 TCC 中的 try。
2)階段 2
如果 try 階段所有業務資源都預留成功,則執行 confirm 操作,否則執行 cancel 操作:
confirm:不做任何業務檢查,僅僅使用預留的資源執行業務操作,如果失敗會一直重試。
cancel:取消執行業務操作,釋放預留的資源,如果失敗會一直重試。
TCC 模式中,事務的發起者和參與者都需要記錄事務日誌,事務的發起者需要記錄全局事務和各個分支事務的狀態和信息;事務的參與者需要記錄分支事務的狀態。
TCC 事務在執行過程中的任意環節,均可能發生宕機、重啟、網絡中斷等異常情況,此時事務處於非原子狀態和非最終一致狀態,此時就需要根據主事務記錄和分支事務記錄的日誌,去完成剩餘分支事務的提交或者回滾,使整個分布式事務內所有參展達到最終一致的狀態,實現事務的原子性。
舉例
我們以一個簡單的電商系統為例,小明在淘寶上花 100 元買了一本書,獲贈 10 個積分,產品上有如下幾個操作:
訂單系統創建商品訂單支付系統接受小明的支付庫存系統扣減產品庫存會員系統給小明帳戶增加會員積分
這幾個動作需要作為一個事務執行,要同時成功或者同時撤銷。
如果採用 TCC 事務模式,那麼各個系統需要改造為如下狀態:
1)訂單系統
try:創建一個訂單,狀態顯示為「待支付」confirm:更新訂單的狀態為「已完成」cancel:更新訂單的狀態為「已取消」
2)支付系統
try:假設小明帳戶中有 1000 元,凍結小明帳戶中的 100 元,此時小明看到的餘額依然是 1000 元。confirm:將帳戶餘額變為 900 元,並清除凍結記錄。concel:清除凍結記錄。
3)庫存系統
try:假設庫存中還生 10 本書,凍結其中的一本書,現實庫存依然有 10 本書。confirm:將剩餘庫存更新為 9 本書,並清除凍結記錄。cancel:清除凍結記錄。
4)會員系統
try:假設小明原因積分 3000 分,給小明帳戶預增加 10 積分,帳戶顯示的積分依然是 3000 分。confirm:將帳戶積分更新為 3010,並清除預增加記錄。cancel:清除預增加記錄。
特點剖析
TCC 事務具備事務的四個特性:
原子性:事務發起方協調各個分支事務全部提交或者全部回滾。一致性:TCC 事務提供最終一致性。隔離型:通過 try 預分配資源的方式來實現數據的隔離。持久性:交由各個分支事務來實現。
TCC 事務模型對業務方侵入較大,需要業務方把功能的實現上由一個接口拆分為三個,開發成本較高。
同時 TCC 事務為了解決異步網絡中的通信失敗或超時帶來的異常情況,要求業務方在設計實現上要遵循三個策略:
允許空回滾:原因是異常發生在階段 1 時,部分參與方沒有收到 try 請求從而觸發整個事務的 cancel 操作,try 失敗或者沒有執行 try 操作的參與方收到 cancel 請求時,要進行空回滾操作。
保持冪等性:原因是異常發生在階段 2 時,比如網絡超時,則會重複調用參與方的 confirm/cancel 方法,因此需要這兩個方法實現上保證冪等性。
防止資源懸掛:原因網絡異常導致兩個階段無法保證嚴格的順序執行,出現參與方側 try 請求比 cancel 請求更晚到達的情況,cancel 會執行空回滾而確保事務的正確性,但是此時 try 方法也不可以再被執行。
TCC 事務將分布式事務從資源層提到業務層來實現,可以讓業務靈活選擇資源的鎖定粒度,並且全局事務執行過程中不會一直持有鎖,所以系統的吞吐量比 2PC/XA 模式要高很多。
支持 TCC 事務的開源框架有:ByteTCC、Himly、TCC-transaction。
Saga
Saga 並不是一個新概念,其相關論文在 1987 年就發布了,和 XA 兩階段提交規範出現的時間差不多。
Saga 和 TCC 一樣,也是一種補償事務,但是它沒有 try 階段,而是把分布式事務看作一組本地事務構成的事務鏈。
事務鏈中的每一個正向事務操作,都對應一個可逆的事務操作。Saga 事務協調器負責按照順序執行事務鏈中的分支事務,分支事務執行完畢,即釋放資源。如果某個分支事務失敗了,則按照反方向執行事務補償操作。
假如一個 Saga 的分布式事務鏈有 n 個分支事務構成,[T1,T2,...,Tn],那麼該分布式事務的執行情況有三種:
T1,T2,...,Tn:n 個事務全部執行成功了。
T1,T2,...,Ti,Ci,...,C2,C1:執行到第 i (i<=n) 個事務的時候失敗了,則按照 i->1 的順序依次調用補償操作。如果補償失敗了,就一直重試。補償操作可以優化為並行執行。
T1,T2,...,Ti (失敗),Ti (重試),Ti (重試),...,Tn:適用於事務必須成功的場景,如果發生失敗了就一直重試,不會執行補償操作。
舉例
假如國慶節小明要出去玩,從北京出發,先去倫敦,在倫敦遊玩三天,再去巴黎,在巴黎遊玩三天,然後再返回北京。整個行程中涉及不同航空公司的機票預訂以及倫敦和巴黎當地的酒店預訂,小明的計劃是如果任何一張機票或酒店預訂不上,就取消本次出行計劃。假如綜合旅遊出行服務平臺提供這種一鍵下單的功能,那麼這就是一個長事務,用 Saga 模式編排服務的話,就如下圖所示:任何一個環節失敗的話,就通過補償操作取消前面的行程預訂。
特點剖析
Saga 事務是可以保障事務的三個特性:
原子性:Saga 協調器可以協調事務鏈中的本地事務要麼全部提交,要麼全部回滾。
一致性:Saga 事務可以實現最終一致性。
持久性:基於本地事務,所以這個特性可以很好實現。
但是 Saga 不保證事務隔離性的,本地事務提交後變更就對其他事務可見了。其他事務如果更改了已經提交成功的數據,可能會導致補償操作失敗。比如扣款失敗,但是錢已經花掉了,業務設計上需要考慮這種場景並從業務設計上規避這種問題。
Saga 事務和 TCC 事務一樣,對業務實現要求高,要求業務設計實現上遵循三個策略:
允許空補償:網絡異常導致事務的參與方只收到了補償操作指令,因為沒有執行過正常操作,因此要進行空補償。
保持冪等性:事務的正向操作和補償操作都可能被重複觸發,因此要保證操作的冪等性。
防止資源懸掛:網絡異常導致事務的正向操作指令晚於補償操作指令到達,則要丟棄本次正常操作,否則會出現資源懸掛問題。
雖然 Saga 和 TCC 都是補償事務,但是由於提交階段不同,所以兩者也是有不同的:
Saga 是不完美補償,補償操作會留下之前原始事務操作的痕跡,需要考慮對業務上的影響。
TCC 是完美補償,補償操作會徹底清理之前的原始事務操作,用戶是感知不到事務取消之前的狀態信息的。
TCC 的事務可以更好的支持異步化,但是 Saga 模式一般在補償階段比較適合異步化。
Saga 模式非常適合於業務流程長的長事務的場景,實現上對業務侵入低,所以非常適合微服務架構的場景。同時 Saga 採用的是一階段提交模式,不會對資源長時間加鎖,不存在「木桶效應」,所以採用這種模式架構的系統性能高、吞吐高。
阿里巴巴的 Seata 開源項目和華為的 ServiceComb 開源項目都支持 Saga 模式。
基於消息的分布式事務
基於消息的分布式事務模式核心思想是通過消息系統來通知其他事務參與方自己事務的執行狀態。
消息系統的引入更有效的將事務參與方解耦,各個參與方可以異步執行。
該種模式的難點在於解決本地事務執行和消息發送的一致性:兩者要同時執行成功或者同時取消執行。
實現上主要有兩種方式:
基於事務消息的方案基於本地消息的方案
基於事務消息的分布式事務
普通消息是無法解決本地事務執行和消息發送的一致性問題的。因為消息發送是一個網絡通信的過程,發送消息的過程就有可能出現發送失敗、或者超時的情況。超時有可能發送成功了,有可能發送失敗了,消息的發送方是無法確定的,所以此時消息發送方無論是提交事務還是回滾事務,都有可能不一致性出現。
解決這個問題,需要引入事務消息,事務消息和普通消息的區別在於事務消息發送成功後,處於 prepared 狀態,不能被訂閱者消費,等到事務消息的狀態更改為可消費狀態後,下遊訂閱者才可以監聽到次消息。
本地事務和事務消息的發送的處理流程如下:
事務發起者預先發送一個事務消息。
MQ 系統收到事務消息後,將消息持久化,消息的狀態是「待發送」,並給發送者一個 ACK 消息。
事務發起者如果沒有收到 ACK 消息,則取消本地事務的執行;如果收到了 ACK 消息,則執行本地事務,並給 MQ 系統再發送一個消息,通知本地事務的執行情況。
MQ 系統收到消息通知後,根據本地事務的執行情況更改事務消息的狀態,如果成功執行,則將消息更改為「可消費」並擇機下發給訂閱者;如果事務執行失敗,則刪除該事務消息。
本地事務執行完畢後,發給 MQ 的通知消息有可能丟失了。所以支持事務消息的 MQ 系統有一個定時掃描邏輯,掃描出狀態仍然是「待發送」狀態的消息,並向消息的發送方發起詢問,詢問這條事務消息的最終狀態如何並根據結果更新事務消息的狀態。因此事務的發起方需要給 MQ 系統提供一個事務消息狀態查詢接口。
如果事務消息的狀態是「可發送」,則 MQ 系統向下遊參與者推送消息,推送失敗會不停重試。
下遊參與者收到消息後,執行本地事務,本地事務如果執行成功,則給 MQ 系統發送 ACK 消息;如果執行失敗,則不發送 ACK 消息,MQ 系統會持續推送給消息。
基於本地消息的分布式事務
基於事務消息的模式對 MQ 系統要求較高,並不是所有 MQ 系統都支持事務消息的,RocketMQ 是目前為數不多的支持事務小的 MQ 系統。如果所依賴的 MQ 系統不支持事務消息,那麼可以採用本地消息的分布式模式。
該種模式的核心思想是事務的發起方維護一個本地消息表,業務執行和本地消息表的執行處在同一個本地事務中。業務執行成功,則同時記錄一條「待發送」狀態的消息到本地消息表中。系統中啟動一個定時任務定時掃描本地消息表中狀態為「待發送」的記錄,並將其發送到 MQ 系統中,如果發送失敗或者超時,則一直發送,知道發送成功後,從本地消息表中刪除該記錄。後續的消費訂閱流程則與基於事務消息的模式雷同。
特點剖析
基於消息的分布式事務模式對 ACID 特性的支持如下:
原子性:最終可以實現分支事務都執行或者都不執行。一致性:提供最終一致性。隔離性:不保障隔離性。持久性:由本地事務來保證。
基於消息的分布式事務可以將分布式系統之間更有效的解耦,各個事務參與方之間的調用不再是同步調用。
對 MQ 系統的要求較高,對業務實現也有一定的侵入性,要麼提供事務消息狀態查詢接口,要麼需要維護本地消息表。並且原則上只接受下遊分支事務的成功,不接受事務的回滾,如果失敗就要一直重試,適用於對最終一致性敏感度較低的業務場景,例如跨企業的系統間的調用,適用的場景有限。
最大努力通知型分布式事務
最大努力通知型的分布式事務解決方案,也是基於 MQ 系統的一種解決方案,但是不要求 MQ 消息可靠。
舉例
假設小明通過聯通的網上營業廳為手機充話費,充值方式選擇支付寶支付。整個操作的流程如下:
小明選擇充值金額「50 元」,支付方式「支付寶」。
聯通網上營業廳創建一個充值訂單,狀態為「支付中」,並跳轉到支付寶的支付頁面(此時進入了支付寶的系統中)。
支付寶驗明確認小明的支付後,從小明的帳戶中扣除 50 元,並向聯通的帳戶中增加 50 元。執行完畢後向 MQ 系統發送一條消息,消息的內容標識支付是否成功,消息發送允許失敗。
如果消息發送成功,那麼支付寶的通知服務會訂閱到該消息,並調用聯通的接口通知本次支付的結果。如果此時聯通的服務掛掉了,導致通知失敗了,則會按照 5min、10min、30min、1h、...、24h 等遞增的時間間隔,間隔性重複調用聯通的接口,直到調用成功或者達到預訂的時間窗口上限後,則不再通知。這就是盡最大努力通知的含義。
如果聯通服務恢復正常,收到了支付寶的通知,如果支付成功,則給帳戶充值;如果支付失敗,則取消充值。執行完畢後給支付寶通知服務確認響應,確認響應允許失敗,支付寶系統會繼續重試。所以聯通的充值接口需要保持冪等性。
如果聯通服務故障時間很久,恢復正常後,已超出支付寶通知服務的時間窗口,則聯通掃描「支付中」的訂單,主動向支付寶發起請求,核驗訂單的支付結果。
特點剖析
最大努力通知型方案本質是通過引入定期校驗機制來對最終一致性做兜底,對業務侵入性較低、對 MQ 系統要求較低,實現比較簡單,適合於對最終一致性敏感度比較低、業務鏈路較短的場景,比如跨平臺、跨企業的系統間的業務交互。
分布式事務中間件
阿里巴巴有兩個分布式事務中間件可選擇:
螞蟻金服團隊開發的 XTS,金融雲產品名稱為 DTX。阿里巴巴中間件團隊開發的 TXC。
XTS 和 TXC 的功能差不多,都支持 TCC 事務模式,也都提供了對業務入侵度較低的分布式事務方案,目前這兩個團隊應該是在共建開源版的分布式事務中間件 Seata。此處我們介紹一下 Seata。
Seata
簡單說一下 Seata (Simple Extensible Autonomous Transaction Architecture) 的歷史:
2014 年阿里巴巴就已經推出了分布式事務中間件產品 TXC (Taobao Transaction Constructor)。
2016 年,TXC 進行了雲產品化改造,提供了阿里雲的雲版本,名字叫做 GTS (Global Transaction Service) 。
2019 年,GTS 宣布開源,開源項目的名字叫做 Seata。
Seata 支持 TCC 模式、Saga 模式。但是 Seata 對 TCC 模式的支持提供了一種對業務入侵度為0的解決方案,這種方案叫做 AT (Automatic Transaction) 模式。下面我們重點說一下 AT 模式的運行機制:
全局事務依然是基於各個分支事務來完成。Seata Server 協調各個分支事務要麼一起提交,要麼一起回滾。
各個分支事務在運行時,Seata Client 通過對 SQL 執行的代理和攔截,通過解析 SQL 定位到行記錄,記錄下 SQL 執行前後的行數據快照,beforeImage 和 afterImage 共同構成了回滾日誌,回滾日誌記錄在獨立的表中。回滾日誌的寫入和業務數據的更改在在同一個本地事務中提交。
分支事務完成後,立即釋放對本地資源的鎖,然後給 Seata 協調器上報事務執行的結果。
Seata 協調器匯總各個分支事務的完成情況,生成事務提交或者回滾的決議,將決議下發給 Seata Client。
如果決議是提交事務,則 Seata Client 異步清理回滾日誌;如果決議是回滾事務,則 Seata Client 根據回滾日誌進行補償操作,補償前會對比當前數據快照和 afterImage 是否一致,如果不一致則回滾失敗,需要人工介入。
AT 模式通過自動生成回滾日誌的方式,使得業務方接入成本低,對業務入侵度很低,但是應用 AT 模式也有一些限制:
AT 模式只支持基於 ACID 事務的關係資料庫。
AT 模式是通過對 SQL 解析來完成的,對 SQL 語法的支持有限,使用複雜 SQL 時需要考慮兼容性。
目前不支持複合主鍵,業務表在設計時注意添加自增主鍵。
全局事務默認的隔離級別是讀未提交,但是通過 SELECT...FOR UPDATE 等語句,可以實現讀已提交的隔離級別。通過全局排它寫鎖,可以做到的隔離級別介於讀未提交和讀已提交之間。
總結
單體資料庫事務很容易滿足事務的 ACID 四個特性,提供強一致性保證,但是分布式事務要完全遵循 ACID 特性會比較困難。為了追求分布式系統的高可用和高吞吐,分布式事務的解決方案一般提供的是最終一致性。
我們把提供強一致性的事務稱之為剛性事務,把提供最終一致性的事務稱之為柔性事務。剛性事務可以完全滿足 ACID 四個特性,柔性事務對事務的 ACID 特性的支持情況如下:
原子性:完全支持。一致性:只提供最終一致性支持。隔離性:不完全保證,通常為了系統的吞吐和性能,會一定程度上放棄對隔離性的要求。持久性:完全支持。
柔性事務一般遵循的是分布式領域中的 BASE 理論:
BA:Basic Availability,基本業務可用性。S:Soft state,柔性狀態。E:Eventual consistency,最終一致性。
BASE 理論,是對 CAP 理論的延伸,是對 CAP 中的一致性和可用性進行一個權衡的結果,理論的核心思想就是:我們無法做到強一致,但每個應用都可以根據自身的業務特點,採用適當的方式來使系統達到最終一致性。
CAP 理論告訴我們一個分布式系統無法同時滿足一致性, 可用性, 分區容錯性,所以在設計上對這三點做取捨。剛性事務追求強一致性,所以犧牲了高可用性;柔性事務通過犧牲一致性換來了系統的高可用性。
在系統選擇分布式方案時,可以根據對一致性的要求進行選擇,業務上有強一致性要求的場景時,優先考慮 XA 規範的兩階段提交;業務上只需要最終一致性的場景時,可以在根據具體場景在柔性事務方案中進行選擇。
參考[1]分布式事務中間件TXC(http://mw.alibaba-inc.com/product-txc.html)[2]彈力設計之補償事務(https://www.jianshu.com/p/8095001d79bb)[3]分布式事務中間件ServiceComb(http://servicecomb.apache.org/cn/docs/distributed-transactions-saga-implementation/)[4]深入理解兩階段提交(https://sq.163yun.com/blog/article/165554812476866560)[5]Seata(https://seata.io/zh-cn/)[6]TCC事務原理(https://www.cnblogs.com/jajian/p/10014145.html)[7]TCC事務異常場景(https://blog.csdn.net/dm_vincent/article/details/92432059[8]Compensating Transaction Pattern(https://docs.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction)[9]基於消息的分布式事務(https://www.jianshu.com/p/04bad986a4a2)[10]分布式事務概述(http://www.tianshouzhi.com/api/tutorials/distributed_transaction/383)[11]初識Open/X XA(https://www.jianshu.com/p/6c1fd2420274)[12]DTP: XA Specification(https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf)[13]DTP Model(https://pubs.opengroup.org/onlinepubs/009249599/toc.pdf)
福利來了
Java 程式設計師學習清單