分佈式基礎(7)-常見分佈式事務解決方案

本文主要參考自相關書籍和網絡文章,並附上自身的一些理解,如有遺漏或錯誤,還望海涵並指出。謝謝!

一.分佈式事務問題及2PC/3PC協議

1.單機ACID事務

傳統的ACID指的是單機情況下(數據庫只存在本地庫),數據庫所具備的原子性、一致性、隔離性與持久性的這四大特性,但是隨着項目越來越大,數據量越來越多,單臺數據庫的磁盤系統被佔滿了或是單張表數據量太大,導致客戶端請求數據庫時存在阻塞問題或者是效率問題,此時的做法是將數據庫進行分庫分表,將數據按一定的規則分配到不同的機器上,此時數據會在多個分佈於不同服務器中的數據庫,所以產生了分佈式事務的問題。

2.分佈式事務產生

分佈式事務指的是跨系統、跨機器之間的事務,由於其不滿足單機的ACID特性,所以相較於普通事務來說複雜了很多。以下是可能產生分佈式事務的一些原因:

  1. 垂直切分:將單個表按業務細化出多張表,每張表存放着不同的字段,當需要使用到多張表時將其連接在一起(join)即可獲取到所需的數據。

  2. 水平切分:使用多臺數據庫或表,將原先位於一個庫或表的數據按某種規則映射到不同的機器上,以此來減少原先單庫或單表中所含的數據大小。

在這裏插入圖片描述
3. 按業務流程拆分:
通常,出現分庫分表的場景還和業務拆分相關,一個很大的系統往往會拆分爲多個小系統,每個小系統之間通過RPC來進行調用,相互協調完成業務,這也會出現分佈式事務的問題:

在這裏插入圖片描述

3.兩階段提交協議

兩階段提交協議(2PC)是處理分佈式事務的一種基本協議,兩階段指的是prepare和commit/rollback階段,並且劃分出了事務管理器與資源管理器角色:

在兩階段提交協議中,有一個事務管理器和多個資源管理器,事務管理器分兩階段協調資源管理器。

在第一階段,事務管理器詢問所有資源管理器準備是否成功(prepare)。

如果所有資源均準備成功,那麼在第二階段事務管理器會要求所有資源管理器執行提交操作(commit)。

如果任一資源管理器在第一階段返回準備失敗,那麼事務管理器會要求所有資源管理器在第二階段執行回滾操作(rollback)。

通過事務管理器的兩階段協調,最終所有資源管理器要麼全部提交,要麼全部回滾,最終狀態都是一致的。

在這裏插入圖片描述

4.三階段提交協議

三階段提交協議(3PC)相較於2PC來說,新增了一個預提交階段(preCommit)與超時機制來再次校驗當前是否全部資源管理器(參與者)都能夠提交成功(或超時),若成功則進行真正的提交階段,若不成功則回滾。

  • 引入超時ACK
    在這裏插入圖片描述

  • 三階段提交成功(commit)
    在這裏插入圖片描述

  • 三階段提交失敗(rollback)
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Ahp0WZYC-1586005545020)(http://note.youdao.com/yws/res/18480/886CAAEECB214AE896D91E88DA18F763)]

二.業務侵入的解決方案

1.消息隊列

對於分佈式事務問題,最簡單的一種方式是使用消息隊列來作爲消息表,在業務的調用流程中通過消息隊列來傳達事務的執行結果,然後下一個流程作爲消費者消費這個執行結果即可。由於要藉助消息隊列來完成這個過程,所以這種做法是有業務侵入的。

1.1、執行過程

在這裏插入圖片描述

如上圖所示,methodA方法與methodB方法分別部署在不同的服務器衆,需要修改不同的數據庫,所以存在分佈式事務問題,如果methodA執行失敗,那麼methodB也應該回滾,methodA與methodB需要同時保證成功與回滾。

所以這裏可以使用一個RocketMQ來實現事務消息的傳達:

1.在執行methodA之前,首先將當前的事務標識封裝成消息並傳入MQ中,此時使用RocketMQ的話可以把這個消息設置爲prepare消息,消費者此時並不會消費掉prepare消息,然後執行methodA方法,此時會出現以下兩種異常回滾情況:

1.1、MQ無法接受消息(宕機或阻塞時間過長):
此時整個流程視作失敗,不會執行到methodA,並且methodB也不會受影響,可以繼續重試發送消息,到一定次數之後拋出異常信息。

1.2、methodA執行失敗:此時由於MQ中的消息是prepare消息,並不會被methodB消費,MQ在一定時間後自動把prepare消息給清除掉。

2.當MQ正常接收到prepare消息,並且methodA也執行成功了,此時將MQ中的該prepare消息的狀態修改爲正式消息,methodB對該消息進行消費,兩者同時成功。


1.2、優缺點

使用MQ解決分佈式事務問題有如下的優點和缺點:

優點:簡單易實現,並且隨着MQ集羣的出現和RocketMQ的prepare機制,使得這種方案具備高可用性和高性能,能達到最終一致性。是最常見的解決方案。

缺點:消費者只能成功,不能失敗,若消費者失敗也不能回滾前者的事務;具有一定的業務侵入性。

2.TCC

1.1、執行過程

TCC是一種經典的2PC解決方案,也就是將整個事務控制過程分爲Try、Confirm和Cancel階段,通過Try階段來對所有的參與者進行資源的檢查與預留,如果Try階段全部成功,那麼就對所有參與者進行Confirm;如果Try階段出現一者失敗,那麼就對所有參與者進行Cancel。

由於Try、Confirm、Cancel 3個方法均由業務編碼實現,所以TCC是具備強業務侵入性的。

在這裏插入圖片描述
例如,現在有兩個系統A和B要做轉賬業務,要從A系統的數據庫中進行扣款,並且對B系統的數據庫中進行款項的增加,如何保證分佈式事務呢?

在使用TCC之前的做法是直接從A中扣款並向B中加款:

update A set money -= 30 where id = 1; # 對A扣款
update B set money += 30 where id = 1; # 對B加款

如果改爲TCC模式的話,那麼有:

  • Try 操作:資源的檢查和預留。在扣款場景,Try 操作要做的事情就是先檢查 A 賬戶餘額是否足夠,再凍結要扣款的 30 元(預留資源);此階段不會發生真正的扣款。
  • Confirm 操作:執行真正業務的提交。在扣款場景下,Confirm 階段做的事情就是發生真正的扣款,把 A 賬戶中已經凍結的 30 元錢扣掉。
  • Cancel 操作:預留資源的釋放。在扣款場景下,扣款取消,Cancel 操作執行的任務是釋放 Try 操作凍結的 30 元錢,使 A 賬戶回到初始狀態。

在這裏插入圖片描述

1.2、併發控制

在實現TCC時,應當考慮併發性問題,將鎖的粒度降到最低,以最大限度提高分佈式事務的併發性。以A賬戶扣款爲例,“賬戶A上有100元,事務T1 要扣除其中的30元,事務T2也要扣除30元,出現併發”。在一階段Try 操作中,分佈式事務T1和分佈式事務T2 分別凍結資金的那一部分資金,相互之間無干擾。

這樣在分佈式事務的二階段,無論T1是提交還是回滾,都不會對T2 產生影響,這樣T1和T2可以在同一筆業務數據上並行執行。

在這裏插入圖片描述

1.3、冪等保證

由於網絡可能出現數據包重傳的情況,所以需要考慮Try、Confirm和Cancel這三個階段的冪等性,也就是Try、Confirm、Cancel 執行一次和執行多次的業務結果是一樣的。

在這裏插入圖片描述

1.4、優缺點

優點:性能提升,具體業務來實現控制資源鎖的粒度變小,不會鎖定整個資源;數據最終一致性 基於Confirm和Cancel的冪等性,保證事務最終完成確認或者取消,保證數據的一致性。

缺點:TCC會侵入業務過程,並且有可能需要修改數據庫表結構來支持。

3.Saga

1.1、執行過程

Saga事務核心思想是將長事務拆分爲多個本地短事務,由Saga事務協調器協調,如果正常結束那就正常完成,如果某個步驟失敗,則根據相反順序一次調用補償操作。

Saga事務基本協議如下:

每個Saga事務由一系列冪等的有序子事務Ti組成。
每個Ti都有對應的冪等補償動作Ci,補償動作用於撤銷Ti造成的結果,補償過程也被稱爲衝正過程

可以看到,和TCC相比,Saga沒有“預留”動作,它的Ti就是直接提交到庫。

在這裏插入圖片描述

例如現在T1、T2、T3爲扣減庫存、創建訂單、支付訂單,如果在支付訂單時失敗了,那麼就對原先的操作做回退,也就是補償衝正:C3支付回滾、C2訂單回滾、C1庫存回滾,使得數據回到最開始的狀態。
在這裏插入圖片描述

1.2、服務編排

可以將Saga的各事務做成服務編排,制訂好每個事務之間的調用順序和回退順序,這樣可以將整個Saga事務的流程清晰化和規範化:
在這裏插入圖片描述

1.3、優缺點

優點:實現簡單,並且整個Saga事務的流程都十分地清晰,基於消息隊列構建的Saga事務還可以避免單點問題。

缺點:具有業務侵入性,需要制訂好每個子事務失敗後對應的回滾(衝正)操作。

三.業務非侵入的解決方案

看完了業務侵入型的解決方案, 下面來看看兩種典型的非業務侵入型解決方案:FMT與XA。

1.FMT

1.1、執行過程

FMT(Framework-managed transaction)即框架管理事務,是一種無侵入的事務解決方案。該模式下,分佈式事務框架會託管所有的事務操作,事務的一階段和二階段操作均由框架自動生成。

FMT、一階段:攔截業務SQL語句,保存SQL執行前的快照,執行SQL,並且添加相應的行鎖,避免出現併發衝突。

在這裏插入圖片描述
FMT、二階段:執行其他業務SQL,若都成功,那麼刪除一階段中產生的鎖和快照;若其一失敗,則重做快照,回滾數據,刪除行鎖。

在這裏插入圖片描述

1.2、優缺點

優點:整個事務處理過程由框架自動化完成,無需人工參與,無業務侵入性。

缺點:由於基於框架來對SQL、事務等進行攔截,所以會有性能損耗(譬如需要使用註解、反射、動態代理等機制)。

2.XA

1.1、執行過程

XA模式是另外一種無侵入的分佈式事務解決方案,不同於FMT的是,XA模式下,所有一階段和二階段都由數據庫來完成,而不是由框架來完成。其原理與FMT相似,都是藉助了快照來完成回退操作。

在這裏插入圖片描述

1.2、優缺點

優點:主流的數據庫都實現了XA分佈式事務方案,所以可以方便地實現。

https://blog.csdn.net/l1028386804/article/details/79769043

缺點:嚴重依賴於數據庫自身的規範和接口,不能高效拓展。

四.總結

在這裏插入圖片描述

分佈式事務的解決基礎是2PC和3PC協議。

2PC和3PC協議都劃分出兩個角色:事務發起者(事務管理器)和跟隨者(資源管理器)。

2PC在第一階段,事務管理器詢問所有資源管理器準備是否成功(prepare)。如果所有資源均準備成功,那麼在第二階段事務管理器會要求所有資源管理器執行提交操作(commit)。如果任一資源管理器在第一階段返回準備失敗,那麼事務管理器會要求所有資源管理器在第二階段執行回滾操作(rollback)。通過事務管理器的兩階段協調,最終所有資源管理器要麼全部提交,要麼全部回滾,最終狀態都是一致的。

3PC相對於2PC來說,增加了超時ACK判斷以及在真正提交之前增加了預提交階段(pre commit)來保證事務能夠全部提交成功。

分佈式事務的常見解決方案分爲兩大類,一類是業務侵入點、另一類是業務非侵入的。

業務侵入的有MQ、TCC、Saga這三種解決方案。MQ的優點是實現簡單並且不會存在單點問題,但是需要使用特定的MQ譬如RocketMQ中的Half Message才能夠滿足需求,並且消費者對於消息的消費是一定需要成功的;TCC是一種經常使用的方案,它的做法是將整個分佈式事務拆分爲三個部分:Try、Confirm和Cancel,在Try階段進行資源的檢查與預留,在第二階段進行事務的統一Confirm和Cancel;Saga的做法是將長事務拆分成順序執行的子事務,如果其中一個子事務執行失敗,則需要繼續相應的事務補償、回滾和數據衝正。

非業務侵入的解決方案有FMT和XA兩種選擇,FMT的思路是由框架來對SQL進行攔截,並且保存之前的快照,在第二個階段中如果全部事務都執行成功那麼就刪除之前的快照並且釋放掉行鎖,如果執行失敗,那麼會執行之前的快照。XA和FMT的做法是類似的,不過XA的兩個階段都由數據庫自身來保證。

最後,其實每一種方案都有各自的優點與缺點,要結合自身業務的情況和系統的特性來選擇具體的方案,選擇性地犧牲某些方面以保證某些方面。

五.Thinks

  • https://www.bilibili.com/video/BV1JE411r7p7?from=search&seid=6646201043947197043
  • https://juejin.im/post/5c0e5bf8e51d45063322fe50#heading-20
  • http://springcloud.cn/view/413#Title-H2-46
  • https://juejin.im/post/5cac36326fb9a06882258c41#heading-2
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章