- 起源 -
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。
- 在整個狀態機啓動時會調用Seata Server開啓分佈式事務,並生產xid, 然後記錄"狀態機實例"啓動事件到本地數據庫。
- 當執行到一個"狀態"時會調用Seata Server註冊分支事務,並生產branchId, 然後記錄"狀態實例"開始執行事件到本地數據庫。
- 當一個"狀態"執行完成後會記錄"狀態實例"執行結束事件到本地數據庫, 然後調用Seata Server上報分支事務的狀態。
- 當整個狀態機執行完成, 會記錄"狀態機實例"執行完成事件到本地數據庫, 然後調用Seata Server提交或回滾分佈式事務。
- Saga Aop Proxy流程示例 -
交易創建訂單事務組正常流程:鎖庫存->減紅包->創建訂單
交易創建訂單事務組異常流程:
- 總結 -
我們已經介紹了XA、2PC、3PC、TCC四種事務模型,但是都不大推薦使用。本文的Saga模式是我主推薦的事務模型,可以適用於大部分的同步事務上。因爲華爲的ServiceComb中的事務模塊目前並非十分獨立,所以強烈推薦Seata。Seata不僅支持Saga模式,,還提供了狀態機的可視化操作製作,使用成本比較底下。而且Seata的AT模式利用數據庫鏡像實現了自動補償機制,又更進一步的優化了Saga模型的缺點。
- 作者介紹 -
林淮川
畢業於西安交通大學;奈學教育《百萬架構師訓練營》講師 和 企業級源碼內源負責人,前大樹金融高級架構師;前大樹金融技術委員會開創者;前大樹金融供應鏈金融技術總監;前天陽宏業交易事業部技術主管;多年互聯網金融行業(ToB)經驗。
孫玄
畢業於浙江大學,奈學教育創始人兼CEO,前轉轉公司技術委員會主席,前58集團技術委員會主席,前百度資深研發工程師,騰訊雲TVP,阿里雲MVP,在線直播大課《百萬架構師》品牌創始人。