ACID和BASE這是事務實現的兩種基礎理論,
ACID是剛性事務,強調的是隔離性和強制一致性,隔離性的話就導致事務操作的資源在事務結束以前要一直被鎖定佔用,又因爲強一致性,如果一個事務中包含了多個子事務,就導致了多個事務一次性完成,但是要是萬一其中一個事務耗時很久,這樣就會導致其他的事務一直佔據着資源沒法釋放,從而影響整個系統的吞吐。
BASE是柔性事務,基本可用 可以保證分佈式事務參與方不一定同時在線。柔性狀態 允許系統狀態更新有一定的延時,這個延時對客戶來說不一定能察覺。最終一致性 通常是通過消息可達的方式保證系統的最終一致性。
什麼叫XA?
XA是一種事務規範,主要是通過兩階段提交來完成分佈式事務,兩階段提交基於ACID理論,這中間主要包括兩個角色:資源管理器和事務管理器,
資源管理器主要負責我們的數據庫等資源,
事務管理器就是一箇中間件主要負責多個事物之間的協調,
場景如下:一次業務請求可能需要兩個事務,
- 第一階段——預提交:首先兩個事務都會去操作自己的數據庫,但是這次操作數據庫並不會commit,也就是說不生效,只是試探性的看看這次操作能否成功,無論成功與否,如果成功的話將會記錄此次的操作記錄,並一直鎖定要操作的數據資源,返回結果給事務管理器,如果失敗則直接回滾所做的操作,並立即釋放鎖定的數據資源,也將結果返回給事務管理器。
- 在第二階段:交易中間件事務管理器收到所有的事務預操作返回結果,並審查所有數據庫返回的預提交結果,如所有數據庫都可以提交,交易中間件將要求所有數據庫做正式提交,這樣該全局事務被提交。而如果有任一數據庫預提交返回失敗,交易中間件將要求所有其它數據庫回滾其操作,這樣該全局事務被回滾。
XA數據源也就是支持XA事務的數據源。
什麼是TCC?
TCC是一種分佈式事務解決方案:Try-Confirm-Cancel,TCC是基於BASE理論,
- Try:嘗試執行業務,完成所有業務的檢查,預留必須的業務資源
- Confirm:確認執行業務,真正的執行業務,不做業務檢查
- Cancel:取消執行業務,釋放Try階段預留的業務資源
上面的解釋可能不太容易明白:舉個例子,你有女朋友,你在某寶要買100包杜蕾斯,這個流程是什麼呢?
Try階段:業務先去檢查庫存還有多少,加入還有1000 然後減去100(被記錄下來) 這個時候庫存剩下900
Confirm階段:根據Try階段的結果,如果滿足100個,也就是操作生效,這個時候業務Try階段減得的庫存就直接生效了
CanCel階段:如果Try階段發現不滿100個,這個時候就根據操作記錄回滾,將庫存再加上100(這個是在Try階段被記錄了的)就行了。
什麼是Saga?
Saga其實是30年前的一篇數據庫論文裏提到的一個概念。在論文中一個Saga事務就是一個長期運行的事務,這個事務是由多個本地事務所組成, 每個本地事務有相應的執行模塊和補償模塊,當saga事務中的任意一個本地事務出錯了, 可以通過調用相關事務對應的補償方法恢復,達到事務的最終一致性。
Saga對服務的要求:冪等性和補償可交換原則
因爲可能因爲網絡問題,會導致出現超時重試的情況,這樣就需要服務支持冪等性,避免多次請求帶來的問題。
重試取消的情況。補償可交換原則是指Saga並行處理的過程中,如果發生了超時重試事件之後,並進行了補償的操作,那麼補償操作是直接生效的。爲了滿足這個要求,需要我們在設計系統的過程中保留所有的事務數據
ACID和Saga
從上面我們可以看出,Saga只支持ACD,不提供隔離性保證。
缺乏隔離性會給我們帶來以下問題:
- 兩個Saga事務同事操作一個資源會出現數據語義不一致的情況
- 兩個Saga同事操作一個訂單,彼此操作會覆蓋對方(更新丟失)
- 兩個Saga事務同時訪問扣款賬號,無法看到退款(髒讀取問題)
- 在一個Saga事務內,數據被其他事務修改前後的讀取值不一致(模糊讀取問題)
如何應對隔離問題:
- 隔離的本質就是控制併發防止併發事務操作相同資源而引起結果錯亂
- 在應用層面加入邏輯鎖的邏輯
- Session層面隔離來保證串行化操作
- 業務層面採用預先凍結資金的方式來隔離此部分資金
- 業務操作過程中通過及時讀取當前的狀態的方式來獲取更新
Saga的兩種實現方式:
集中式的實現方式:集中式協調器負責服務調用以及事務協調
分佈式的實現方式:通過事件驅動的方式進行事務的協調
集中式的Saga實現一般是通過一個Saga對象來追蹤所有的Saga子任務的調用情況, 根據調用情況來決定是否需要調用對應的補償方面,協調器和調用方是在一個進程中的。缺點就是耦合度太高。
分佈式的Saga的實現使用過事件驅動的,相關的服務監聽相關的事件,從而觸發該服務,因此分佈式Saga也叫事務編排
分佈式事務的好處是:降低了耦合性以及系統的複雜性,系統的邏輯處理是基於事件。
舉個具體的例子:我們現在的系統中就是基於分佈式Saga處理的,我們是通過Kafka作爲消息中間件,
每個服務訂閱相關的Channel,當捕獲相關的事件之後就自動觸發服務。這裏面最重要的是要持久化相關的環節,比如持久化事件信息以及中間信息,因爲事務出現回滾或者補償的時候會需要這些信息。
微服務事務的一致性建議:內剛外柔
內剛:在微服務內部通過數據庫事務保證強一致性
外柔:在微服務之間的保證服務的最終一致性
參考鏈接:https://servicecomb.apache.org/cn/docs/distributed-transactions-saga-implementation/