分佈式架構設計篇(九)-柔性事務之Saga詳解

                                                                                             -     起源     -

Saga模型起源於1987年 Hector Garcia-Molina,Kenneth Salem 發表的論文《Sagas》,是分佈式事務相關概念最早出現的。

Saga模型是把一個分佈式事務拆分爲多個本地事務,每個本地事務都有相應的執行模塊和補償模塊(對應TCC中的Confirm和Cancel),當Saga事務中任意一個本地事務出錯時,可以通過調用相關的補償方法恢復之前的事務,達到事務最終一致性。

                                                                                          -     組成     -

  • Saga模型主要分:

    •  一串子事務(本地事務)的事務鏈

    • 每個Saga子事務Tn, 都有對應的補償定義 Cn用於撤銷Tn造成的結果

    • 每個Tn都沒有“預留”動作,直接提交到庫。

  • 執行順序:

    • 子事務序列 T1, T2, …, Tn得以完成 (最佳情況)

    • 或者序列 T1, T2, …, Tj, Cj-1, …, C2, C1, 0 < j < n, 得以完成

  • 數據隔離性:

    • 業務層控制併發

    • 在應用層加鎖

    • 應用層預先凍結資源等

  • 恢復方式:

    • 向後恢復:補償所有已完成的事務,如果任一子事務失敗

    • 向前恢復:重試失敗的事務,假設每個子事務最終都會成功 

從Saga模型的上述定義中,Saga 模型可以滿足事務的三個特性:

  • 原子性:Saga 協調器協調事務鏈中的本地事務要麼全部提交,要麼全部回滾。

  • 一致性:Saga 事務可以實現最終一致性。

  • 持久性:基於本地事務,所以這個特性可以很好實現。

從數據隔離性上分析,我們可以發現Saga模型無法保證外部的原子性和隔離性,因爲可以查看其他sagas的部分結果,論文中有對應的表述:

 

                                                                                        -     注意事項     -

Saga 事務和 TCC 事務一樣,都是強依靠業務改造,所以要求業務方在設計上要遵循三個策略:

  • 允許空補償:網絡異常導致事務的參與方只收到了補償操作指令,因爲沒有執行過正常操作,因此要進行空補償。

  • 保持冪等性:事務的正向操作和補償操作都可能被重複觸發,因此要保證操作的冪等性。

  • 防止資源懸掛:原因是網絡異常導致事務的正向操作指令晚於補償操作指令到達,則要丟棄本次正常操作,否則會出現資源懸掛問題。

                                                                                     -     Saga和TCC對比     -

雖然 Saga 和 TCC 都是補償事務,但是由於提交階段不同,所以兩者也是有不同的:

  • Saga 沒有Try行爲,直接Commit,所以會留下原始事務操作的痕跡,Cancel屬於不完美補償,需要考慮對業務上的影響。TCC Cancel是完美補償的Rollback,補償操作會徹底清理之前的原始事務操作,用戶是感知不到事務取消之前的狀態信息的。

  • Saga 的補償操作通常可以異步執行,TCC的Cancel和Confirm可以跟進需要是否異步化。

  • Saga 對業務侵入較小,只需要提供一個逆向操作的Cancel即可;而TCC需要對業務進行全局性的流程改造。

  • TCC最少通信次數爲2n,而Saga爲n(n=子事務的數量)。

                                                                                       -     Saga實現     -

目前業界提供了兩類Saga的實現方式,一種是基於業務邏輯層Proxy設計(基於AOP實現),比如華爲的ServiceComb;一種是狀態機實現的機制,比如阿里的Seata的Saga模式。

Aop Proxy實現原理如下:

業務邏輯層調用上加上事務註解@Around(“execution(* *(..)) && @annotation(TX)”),Proxy在真正業務邏輯被調用之前, 生成一個全局唯一 TXID 標示事務組,TXID保存在ThreadLocal變量裏,方法開始前寫入,完成後清除,並向遠端數據庫寫入 TXID 並把事務組置爲開始狀態。業務邏輯層調用數據訪問層之前,通過RPCProxy代理記錄當前調用請求參數。如果業務正常,調用完成後,當前方法的調用記錄存檔或刪除。如果業務異常,查詢調用鏈反向補償

數據訪問層設計:原始接口必須保證冪等性,滿足本地原子性。提供補償接口實現反向操作。這方面可以在框架層面做一些通用補償實現,降低使用成本,當然補償接口也是必須也有冪等性保證。還可以提供補償註解,基於原則接口方法,在方法名加註解標註補償方法名:@Compensable(cancelMethod=“cancelRecord”)

補償策略:首先是調用執行失敗,修改事務組狀態;其次分佈式事務補償服務異步執行補償

狀態機引擎Saga原理如下:流程爲--先執行stateA, 再執行stateB,然後執行stateC

"狀態"的執行是基於事件驅動的模型,stateA執行完成後,會產生路由消息放入EventQueue,事件消費端從EventQueue取出消息,執行stateB。

  1. 在整個狀態機啓動時會調用Seata Server開啓分佈式事務,並生產xid, 然後記錄"狀態機實例"啓動事件到本地數據庫。
  2. 當執行到一個"狀態"時會調用Seata Server註冊分支事務,並生產branchId, 然後記錄"狀態實例"開始執行事件到本地數據庫。
  3. 當一個"狀態"執行完成後會記錄"狀態實例"執行結束事件到本地數據庫, 然後調用Seata Server上報分支事務的狀態。
  4. 當整個狀態機執行完成, 會記錄"狀態機實例"執行完成事件到本地數據庫, 然後調用Seata Server提交或回滾分佈式事務。

                                                                          -     Saga Aop Proxy流程示例     -

交易創建訂單事務組正常流程:鎖庫存->減紅包->創建訂單

交易創建訂單事務組異常流程:

 

                                                                                          -     總結     -

我們已經介紹了XA、2PC、3PC、TCC四種事務模型,但是都不大推薦使用。本文的Saga模式是我主推薦的事務模型,可以適用於大部分的同步事務上。因爲華爲的ServiceComb中的事務模塊目前並非十分獨立,所以強烈推薦Seata。Seata不僅支持Saga模式,,還提供了狀態機的可視化操作製作,使用成本比較底下。而且Seata的AT模式利用數據庫鏡像實現了自動補償機制,又更進一步的優化了Saga模型的缺點。

                                                                                       -     作者介紹    -

林淮川

畢業於西安交通大學;奈學教育《百萬架構師訓練營》講師 和 企業級源碼內源負責人,前大樹金融高級架構師;前大樹金融技術委員會開創者;前大樹金融供應鏈金融技術總監;前天陽宏業交易事業部技術主管;多年互聯網金融行業(ToB)經驗。

孫玄

畢業於浙江大學,奈學教育創始人兼CEO,前轉轉公司技術委員會主席,前58集團技術委員會主席,前百度資深研發工程師,騰訊雲TVP,阿里雲MVP,在線直播大課《百萬架構師》品牌創始人。

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