githubgit
1987年普林斯頓大學的Hector Garcia-Molina和Kenneth Salem發表了一篇Paper Sagas,講述的是如何處理long lived transaction(長活事務)。聽起來是否是以爲和分佈式事務很像?沒錯,下面來看看這個來自1987年的解決方案是如何啓發當今的分佈式事務問題的。github
Saga的組成:apache
能夠看到,和TCC相比,Saga沒有「預留」動做,它的Ti就是直接提交到庫。segmentfault
Saga的執行順序有兩種:分佈式
Saga定義了兩種恢復策略:中間件
Saga對於ACID的保證和TCC同樣:接口
Saga相比TCC的缺點是缺乏預留動做,致使補償動做的實現比較麻煩:Ti就是commit,好比一個業務是發送郵件,在TCC模式下,先保存草稿(Try)再發送(Confirm),撤銷的話直接刪除草稿(Cancel)就好了。而Saga則就直接發送郵件了(Ti),若是要撤銷則得再發送一份郵件說明撤銷(Ci),實現起來有一些麻煩。事務
若是把上面的發郵件的例子換成:A服務在完成Ti後當即發送Event到ESB(企業服務總線,能夠認爲是一個消息中間件),下游服務監聽到這個Event作本身的一些工做而後再發送Event到ESB,若是A服務執行補償動做Ci,那麼整個補償動做的層級就很深。ci
不過沒有預留動做也能夠認爲是優勢:資源
對於服務來講,實現Saga有如下這些要求:
第一點要求Ti和Ci是冪等的,舉個例子,假設在執行Ti的時候超時了,此時咱們是不知道執行結果的,若是採用forward recovery策略就會再次發送Ti,那麼就有可能出現Ti被執行了兩次,因此要求Ti冪等。若是採用backward recovery策略就會發送Ci,而若是Ci也超時了,就會嘗試再次發送Ci,那麼就有可能出現Ci被執行兩次,因此要求Ci冪等。
第二點要求Ci必須可以成功,這個很好理解,由於,若是Ci不能執行成功就意味着整個Saga沒法徹底撤銷,這個是不容許的。但總會出現一些特殊狀況好比Ci的代碼有bug、服務長時間崩潰等,這個時候就須要人工介入了。
第三點乍看起來比較奇怪,舉例說明,仍是考慮Ti執行超時的場景,咱們採用了backward recovery,發送一個Ci,那麼就會有三種狀況:
對於第1種狀況,容易處理。對於第二、3種狀況,則要求Ti和Ci是可交換的(commutative),而且其最終結果都是sub-transaction被撤銷。