微服务--分布式事务的实现方法及替代方案
這兩天正在研究微服務架構中分布式事務的處理方案, 做一個小小的總結, 作為備忘. 如有錯誤, 歡迎指正!
概念澄清
事務補償機制: 在事務鏈中的任何一個正向操作, 都必須存在一個完全符合回滾規則的可逆操作, 這個操作通常叫做rollback或者cancel.
CAP理論: CAP(Consistency, Availability, Partition Tolerance), 闡述了一個分布式系統的三個主要方面, 只能同時擇其二進行實現. 常見的有CP系統, AP系統.
為什么CA不行呢? 因為沒有P的話, 數據一致性會出現問題, 這是任何一個一致性系統不允許出現的情況.
冪等性: 簡單的說, 業務操作支持重試, 不會產生不利影響. 常見的實現方式: 為消息額外增加唯一ID.
BASE(Basically avaliable, soft state, eventually consistent): 是分布式事務實現的一種理論標準.
柔性事務 vs. 剛性事務
剛性事務是指強一致性事務, 例如單機環境下遵循ACID的數據庫事務, 或者分布式環境中的2PC等.
柔性事務是指遵循BASE理論的事務, 通常用在分布式環境中, 常見的實現方式有: 異步確保型, 最大努力通知型.
最佳實踐
先上結論, 再分別介紹分布式事務的各種實現方式.
如果業務場景需要強一致性, 那么盡量避免將它們放在不同服務中, 也就是盡量使用本地事務, 避免使用強一致性的分布式事務(例如2PC).
如果業務場景能夠接受最終一致性, 那么最好是使用異步確保型來解決(實際上大部分互聯網公司的業務都是這么玩兒的).
注意: 以下每種方案都有不同的適用場合, 需要根據實際業務場景來選擇.
兩階段提交(2PC)
兩階段提交(Two Phase Commit, 2PC), 具有強一致性, 是CP系統的一種典型實現, 是數據庫層面的強一致性事務實現.
兩階段提交, 常見的標準是XA等. 例如Oracle的數據庫支持XA, MySQL從5.5開始支持XA.
下圖是兩階段提交的示意圖:
圖的上半是兩階段提交成功的演示, 下半是兩階段提交失敗的演示. 關于兩階段提交網上有很多經典的講解, 這里就不細說了, 可以參考前面的鏈接.
優點
依賴數據庫服務提供商的XA實現來使用2PC, 無需像TCC那樣每個服務都需要手工編寫TCC接口實現類.
缺點
事務管理器單點失敗
高并發不適用, 資源加鎖時間較長, 無法靈活控制鎖粒度(db層面的鎖在2PC期間會一直被持有, 相較于TCC而言不靈活, 因為無法在tcc的中間階段解鎖.).
TCC (Try-Confirm-Cancle)
TCC是應用層的2PC, 具有最終一致性.
以上圖中的A->B實時匯款服務為例. 假設匯款服務和收款服務位于兩個不同的微服務中.
首先服務主調方充當事務管理器的角色, 注冊匯款收款服務的TCC接口.
事務開始, 進入TCC事務中的TRY階段.
調用匯款服務的try接口, 檢查A賬戶有效性(不在凍結狀態), 余額充足性, 并扣減轉賬金額.
調用收款服務的try接口, 檢查B賬戶的有效性(不為凍結狀態).
檢查所有被調服務的try返回值:
如果任一服務try失敗, 那么會自動調用所有服務對應的cancel方法, 對于A賬戶, 就是將余額加回; 對于B賬戶, 不做任何操作.
如果所有服務的try均成功, 那么會自動調用所有服務對應的confirm方法, 對于A賬戶, 不做任何操作; 對于B賬戶, 增加匯款金額
注意: 如果任一cancel或confirm失敗, 需要不斷重試直到成功或人工介入.
事務結束.
優點
對比與前面提到的2PC, 主要優勢是:
可自由控制鎖粒度(在應用層控制);
缺點
事務管理器單點失敗.
每個服務都要實現TCC接口, 較為復雜.
若允許并發操作, Confirm和Cancel操作無法冪等(可通過額外信息例如唯一事務id實現).
因為數據庫級別的事務不允許臟讀, 不存在數據一致性問題, 所以數據庫級別的rollback設計是冪等的; 而TCC為了避免數據一致性問題, 只能通過補償型操作實現. 這就導致Confirm和Cancel操作本身不可能冪等, 解決方案有兩種:
通過事務id操作去重;
在confirm或cancel階段, 只有明確收到confirm或cancel的失敗反饋才能重試, 否則需要log而后人工介入.
適用場景
嚴格一致性
執行時間短
實時性要求高
舉例: 紅包, 收付款, 實時匯款業務.
異步確保型
通過將一系列同步的事務操作變為基于消息執行的異步操作, 避免了分布式事務中的同步阻塞操作的影響.
這個方案真正實現了兩個服務的解耦, 解耦的關鍵就是異步消息和補償性事務.
這里以一個例子作為講解:
執行步驟如下:
MQ發送方發送遠程事務消息到MQ Server;
MQ Server給予響應, 表明事務消息已成功到達MQ Server.
MQ發送方Commit本地事務.
若本地事務Commit成功, 則通知MQ Server允許對應事務消息被消費; 若本地事務失敗, 則通知MQ Server對應事務消息應被丟棄.
若MQ發送方超時未對MQ Server作出本地事務執行狀態的反饋, 那么需要MQ Servfer向MQ發送方主動回查事務狀態, 以便進一步處理未投遞的事務消息(丟棄或投遞).
當得知本地事務執行成功時, MQ Server允許MQ訂閱方消費本條事務消息.
消費者消費完之后, 需要ack到MQ Server, 之后事務消息才能從MQ Server刪除. 否則消費者需要一直重試, 直到成功或者人工介入.
注意事項
消息中間件在系統中扮演一個重要的角色, 所有的事務消息都需要通過它來傳達, 所以消息中間件也需要支持HAC來確保事務消息不丟失.
根據業務邏輯的具體實現不同,還可能需要對消息中間件增加消息不重復, 不亂序等其它要求.
適用場景
執行周期較長
實時性要求不高
例如:
非實時匯款業務
退貨/退款業務
財務, 賬單統計業務(先發送到消息中間件, 而后可進行批量記賬)
最大努力通知型
這是分布式事務中要求最低的一種, 也可以通過消息中間件實現, 與前面異步確保型操作不同的一點是, 在消息由MQ Server投遞到消費者之后, 允許在達到最大重試次數之后直接結束事務, 無需人工介入確保成功.
優點
高并發, 低耦合
缺點
不支持回滾;
適用場景
交易結果消息的通知等.
SAGA
將一個大事務拆成一串小事務, 分段提交和回滾.
可能的執行序列:
成功: T1, T2, T3, …, Tn;
失敗: T1, T2, , T3, …, Tn-1, Cn-1, Cn-2, Cn-3, …, C1
缺點
有數據一致性問題:
舉個例子, 定義:
T1=扣100元 T2=給用戶加一瓶水 T3=減庫存一瓶水
C1=加100元 C2=給用戶減一瓶水 C3=給庫存加一瓶水
如果在T3失敗進行回滾, 此時用戶已經把水喝了, 那么就會造成回滾失敗, 出現數據一致性問題. 根本原因是沒有了tcc的try階段預留資源導致的. 解決方案就是要么在所有資源上加鎖, 要么嚴格控制t的順序, 將回滾困難的放在最后.
小結
不管是同步事務中的事務管理器(協調者), 還是異步事務中使用的消息中間件,若要達到一致性保證,都需要使用帶有同步復制語義的HAC提供的高可用和高可靠特性,這些都是以性能為代價的,無疑成為了SOA架構中的典型性能瓶頸之一.
不同方案對比
本文鏈接: http://blog.csdn.net/congyihao/article/details/70195154
參考鏈接
支付寶運營架構中柔性事務指的是什么?
分布式服務的事務如何處理?
理解分布式事務的兩階段提交2pc
阿里云消息隊列MQ-發送事務消息
Github: tcc-transaction
————————————————
版權聲明:本文為CSDN博主「congyh」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/congyihao/article/details/70195154
總結
以上是生活随笔為你收集整理的微服务--分布式事务的实现方法及替代方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 买股票好还是买基金好?主要从以下几点考虑
- 下一篇: 大额信用卡怎么办理?信用卡额度相关问题分