這裏寫自定義目錄標題
Sagas
每個Sagas由一系列sub-transaction Ti (saga)組成
每個Ti 都有對應的補償動作Ci,補償動作用於撤銷Ti造成的結果
可以看到,和TCC相比,Saga沒有“預提交”階段,它的Ti就是直接提交到庫。
-
Sagas兩種可能的執行流程
- T1, T2, T3, …, Tn
- T1, T2, …, Ti, Ci,…, C2, C1,其中0 < i < n
-
Sagas的 恢復策略
- backward recovery,向後恢復,補償所有已完成的事務,如果任一子事務失敗。即上面提到的第二種執行順序,其中j是發生錯誤的sub-transaction,這種做法的效果是撤銷掉之前所有成功的sub-transation,使得整個Sagas的執行結果撤銷。
- forward recovery,向前恢復,重試失敗的事務,假設每個子事務最終都會成功。適用於必須要成功的場景,執行順序是類似於這樣的:T1, T2, …, Tj(失敗), Tj(重試),…, Tn,其中j是發生錯誤的sub-transaction。該情況下不需要Ci。
-
Sagas的使用注意事項
- 只允許兩層嵌套,整個事務我們叫主事務(Sagas)和子事務Saga,子事務(saga)是互相獨立的原子操作。
- Sagas不保證ACID,只保證最終一致性。即Ci必須保證成功,即使系統不能成功也需要人工干預,這種情況下需要saga log支持。
- 基於上面,整個Sagas事務無原子性特徵,即一個Sagas可以看到另外一個Sagas的中間狀態,即部分結果
- Ti、Ci需要冪等,且先後執行Ti、Ci即使順序不同也能保證結果一致,即事務被撤銷
- 補充事務Ci從語義上撤銷了Ti的影響,但不一定能讓系統/數據庫回到原先的狀態。例如Ti將郵件發送出去了,Ti發射了魚雷。這裏需要特別注意
-
Sagas的優缺點和使用場景
由於saga直接提交事務而沒有TCC的Try的階段,所以減少了一次通信成本,效率更高,但對於複雜的事務,提供補充機制的成本可能很高,同樣沒有預提交也沒有資源釋放及異常處理的問題,這點和TCC相比算是各有優勢;另外對於長事務,即i值較大時,回退的流程可能很長,性能和效率會有較大影響;最後,沒有預提交階段,存證上節提到的Ci無法保證系統的整體狀態回到Ti發生前。
基於此的場景:- 較簡單的業務,提供補充Ci較簡單
- 系統集成,其中遺留子系統或第三方服務無法提供預提交(Try)能力的情況,只需要增加補償機制即可實現
Sagas 的實現範式
下面以一個電商系統爲例,該案例中Saga的實現層,基於一個可持久化且可靠的消息系統實現
- ** 基於編排模式(Choreography)**
基於編排的Sagas創建訂單,包含以下步驟:
- 在Order Service接收到該POST /orders請求並創建一個PENDING狀態的Order
- 然後發出一個Order Created事件
- Customer Service的事件處理程序嘗試扣減信用(信用卡消費)
- 然後Customer Service發出一個指示結果的事件
- OrderService的事件處理程序完成或拒絕Order
- ** 基於編制模式(Orchestration)**
基於編制的Sagas創建訂單,包含以下步驟:
- 在Order Service接收到該POST /orders請求並創建Create Order Sagas協調器(orchestrator,可看作一個編制的api,後續介紹服務編排會再提到)
- Sagas協調器創建一個PENDING狀態的Order
- 然後,它發送Reserve Credit命令到Customer Service
- Customer Service嘗試扣減信用
- 然後,Customer Service發送回包含結果的回覆消息
- Sagas協調器完成或拒絕 Order