分佈式事務常見解決方案

分佈式事務產生的原因

1. 數據庫分庫分表

        當數據庫單表數據量超過2000W,就要考慮分庫分表,這時候,如果一個操作既訪問01庫,又訪問02庫,而且要保證數據的一致性,那麼就要用到分佈式事務。

2. 應用服務化

         業務的服務化。比如原來單機支撐的應用服務,拆解爲一塊一塊獨立的服務,例如用戶中心、訂單中心、賬戶中心、庫存中心。對於訂單中心,有專門的數據庫存儲訂單信息,用戶中心也有專門的數據庫存儲用戶信息,庫存中心也會有專門的數據庫存儲庫存信息。這時候如果要同時對訂單進行操作,那麼就會涉及到訂單數據庫和賬戶數據庫,爲了保證數據一致性,就需要用到分佈式事務。

行業中常見解決方案

1. 本地消息表(異步確保)

本地消息表這種實現方式應該是業界使用最多的,其核心思想是將分佈式事務拆分成本地事務進行處理,這種思路是來源於ebay。

基本思路:

  • 消息生產方:需要額外建一個本地消息表,並記錄消息發送狀態。消息表和業務數據要在一個事務裏提交,也就是說他們要在一個數據庫裏面。然後一個定時任務定時查詢該消息列表的消息,並將消息經過MQ發送到消息的消費方。如果消息發送失敗,會進行重試發送。
  • 消息消費方:需要接受並處理生產方發送的消息,並完成自己的業務邏輯。此時如果本地事務處理成功,表明已經處理成功了,如果處理失敗,那麼就會重試執行。如果是業務上面的失敗,可以給生產方發送一個業務補償消息,通知生產方進行回滾等操作。消息消費方要保證接口冪等性。
  • 生產方定時掃描本地消息表,把還沒處理完成的消息或者失敗的消息再發送一遍。

生產方保證業務消息原子性:要用本地消息列表的原因是要通過本地事務保證業務和消息的原子性操作,如果直接跟消息中間件發送消息,可能會出現

(1)、業務處理成功但是消息發送超時,此時本地業務數據回滾了,但是消息最終成功了(先處理本地業務數據後發送消息);

begin transaction;
		// 1.數據庫操作
		// 2.發送MQ
commit transation;

(2)、或者出現消息發送成功了,但是本地業務處理失敗,無法回滾消息(先發送消息,後處理本地業務)。

begin transaction;
		// 1.發送MQ
		// 2.數據庫操作
commit transation;		

 消費方接口冪等性:一個消息的狀態如果未標記爲消費成功,消息中間件會重複投遞此消息,就導致來消息的重複消費。要解決消息重複消費的問題就要實現事務參與方的方法冪等性

2. 兩階段提交

XA是X/Open CAE Specification (Distributed Transaction Processing)模型中定義的TM(Transaction Manager)與RM(Resource Manager)之間進行通信的接口。

兩階段提交是XA的標準實現。它將分佈式事務的提交拆分爲2個階段:prepare和commit/rollback。

在XA規範中,數據庫充當RM角色,應用需要充當TM的角色,即生成全局的txId,調用XAResource接口,把多個本地事務協調爲全局統一的分佈式事務。

XA中有兩個重要的概念:事務管理器和本地資源管理器。其中本地資源管理器往往由數據庫實現,比如Oracle、DB2這些商業數據庫都實現了XA接口,而事務管理器作爲全局的調度者,負責各個本地資源的提交和回滾。XA實現分佈式事務的原理如下:

特點:

        XA協議比較簡單,目前很多商業數據庫(Oracle,DB2、MySQL從5開始支持)都實現XA協議,使用分佈式事務的成本也比較低。

        但是,XA也有致命的缺點,那就是性能不理想,特別是在交易下單鏈路,往往併發量很高,XA無法滿足高併發場景。XA目前在商業數據庫支持的比較理想,在mysql數據庫中支持的不太理想,mysql的XA實現,沒有記錄prepare階段日誌,主備切換會導致主庫與備庫數據不一致。許多nosql也沒有支持XA,這讓XA的應用場景變得非常狹隘。在prepare階段需要等待所有參與子事務的反饋,因此可能造成數據庫資源鎖定時間過長,不適合併發高以及子事務生命周長較長的業務場景。兩階段提交這種解決方案屬於犧牲了一部分可用性來換取的一致性。

補充:二階段提交協議的主要缺點:

       同步阻塞:二階段提交協議存在的最明顯也是最大的問題就是同步阻塞,這會極大地限制分佈式系統的性能。在二階段提交的執行過程中,所有參與該事務操作的邏輯都處於阻塞狀態,各個參與者在等待其他參與者響應的過程中,將無法進行其他任何操作。

       單點問題:一旦協調者出現問題,整個二階段提交流程將無法運轉。

       數據不一致:在二階段的第二個階段(執行事務提交)的時候,當協調者向所有的參與者發送Commit請求之後,發生了局部網絡異常或者協調者在尚未發送完Commit請求之前自身發生崩潰,最終只有部分參與者收到了Commit請求。於是這部分收到了Commit請求的參與者就會進行事務提交,而其他沒有收到Commit請求的參與者無法進行事務提交,這樣就出現數據不一致。

3. 事務消息+最終一致性

事務消息作爲一種異步確保型事務, 將兩個事務分支通過MQ進行異步解耦,事務消息的設計流程同樣借鑑了兩階段提交理論。

  • 事務發起方首先發送prepare消息到MQ。

  • 在發送prepare消息成功後執行本地事務。

  • 根據本地事務執行結果返回commit或者是rollback。

  • 如果消息是rollback,MQ將刪除該prepare消息不進行下發,如果是commit消息,MQ將會把這個消息發送給consumer端。

  • 如果執行本地事務過程中,執行端掛掉,或者超時,MQ將會不停的詢問其同組的其它producer來獲取狀態。

  • Consumer端的消費成功機制有MQ保證。

基於消息中間件的兩階段提交往往用在高併發場景下,將一個分佈式事務拆成一個消息事務(A系統的本地操作+發消息)+B系統的本地操作,其中B系統的操作由消息驅動,只要消息事務成功,那麼A操作一定成功,消息也一定發出來了,這時候B會收到消息去執行本地操作,如果本地操作失敗,消息會重投,直到B操作成功,這樣就變相地實現了A與B的分佈式事務

特點:第三方的MQ是支持事務消息的,比如RocketMQ,但是市面上一些主流的MQ都是不支持事務消息的,比如 RabbitMQ 和 Kafka 都不支持。

4. 補償事務(TCC)

TCC 其實就是採用的補償機制,其核心思想是:針對每個操作,都要註冊一個與其對應的確認和補償(撤銷)操作。TCC模型是把鎖的粒度完全交給業務處理。它分爲三個階段:

  • Try 階段主要是對業務系統做檢測及資源預留

  • Confirm 階段主要是對業務系統做確認提交,Try階段執行成功並開始執行 Confirm階段時,默認 Confirm階段是不會出錯的。即:只要Try成功,Confirm一定成功。

  • Cancel 階段主要是在業務執行錯誤,需要回滾的狀態下執行的業務取消,預留資源釋放。

特點:TCC模型對業務的侵入強,改造的難度大。

 

擴展閱讀:https://www.cnblogs.com/bluemiaomiao/p/11216380.html

https://blog.csdn.net/zhao1299002788/article/details/103283158

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章