天天看點

微服務--分布式事務的實作方法及替代方案

這兩天正在研究微服務架構中分布式事務的處理方案, 做一個小小的總結, 作為備忘. 如有錯誤, 歡迎指正!

概念澄清

  • 事務補償機制: 在事務鍊中的任何一個正向事務操作, 都必須存在一個完全符合復原規則的可逆事務.
  • CAP理論: CAP(Consistency, Availability, Partition Tolerance), 闡述了一個分布式系統的三個主要方面, 隻能同時擇其二進行實作. 常見的有CP系統, AP系統.
  • 幂等性: 簡單的說, 業務操作支援重試, 不會産生不利影響. 常見的實作方式: 為消息額外增加唯一ID.
  • BASE(Basically avaliable, soft state, eventually consistent): 是分布式事務實作的一種理論标準.

柔性事務 vs. 剛性事務

剛性事務是指嚴格遵循ACID原則的事務, 例如單機環境下的資料庫事務.

柔性事務是指遵循BASE理論的事務, 通常用在分布式環境中, 常見的實作方式有: 兩階段送出(2PC), TCC補償型送出, 基于消息的異步確定型, 最大努力通知型.

通常對本地事務采用剛性事務, 分布式事務使用柔性事務.

最佳實踐

先上結論, 再分别介紹分布式事務的各種實作方式.

  • 如果業務場景需要強一緻性, 那麼盡量避免将它們放在不同服務中, 也就是盡量使用本地事務, 避免使用強一緻性的分布式事務.
  • 如果業務場景能夠接受最終一緻性, 那麼最好是使用基于消息的最終一緻性的方案(異步確定型)來解決.
  • 如果業務場景需要強一緻性, 并且隻能夠進行分布式服務部署, 那麼最好是使用TCC方案而不是2PC方案來解決.

注意: 以下每種方案都有不同的适用場合, 需要根據實際業務場景來選擇.

兩階段送出(2PC)

兩階段送出(Two Phase Commit, 2PC), 具有強一緻性, 是CP系統的一種典型實作.

兩階段送出, 常見的标準是XA, JTA等. 例如Oracle的資料庫支援XA.

下圖是兩階段送出的示意圖:

微服務--分布式事務的實作方法及替代方案

2pc

圖的上半是兩階段送出成功的示範, 下半是兩階段送出失敗的示範. 關于

兩階段送出

網上有很多經典的講解, 這裡就不細說了, 可以參考前面的連結.

缺點

  • 兩階段送出中的第二階段, 協調者需要等待所有參與者發出yes請求, 或者一個參與者發出no請求後, 才能執行送出或者中斷操作. 這會造成長時間同時鎖住多個資源, 造成性能瓶頸, 如果參與者有一個耗時長的操作, 性能損耗會更明顯.
  • 實作複雜, 不利于系統的擴充, 不推薦.

TCC (Try-Confirm-Cancle)

TCC, 是基于補償型事務的AP系統的一種實作, 具有最終一緻性.
微服務--分布式事務的實作方法及替代方案

TCC流程

下面以客戶購買商品時的付款操作為例進行講解:

  • Try:

    完成所有的業務檢查(一緻性),預留必須業務資源(準隔離性);

    展現在本例中, 就是确認客戶賬戶餘額足夠支付(一緻性), 鎖住客戶賬戶, 商戶賬戶(準隔離性).

  • Confirm:

    使用Try階段預留的業務資源執行業務(業務操作必須是幂等的), 如果執行出現異常, 要進行重試.

    在這裡就是執行客戶賬戶扣款, 商戶賬戶入賬操作.

  • Cancle:

    釋放Try階段預留的業務資源, 在這裡就是釋放客戶賬戶和商戶賬戶的鎖;

    如果任一子業務在Confirm階段有操作無法執行成功, 會造成對業務活動管理器的響應逾時, 此時要對其他業務執行補償性事務. 如果補償操作執行也出現異常, 必須進行重試, 若實在無法執行成功, 則事務管理器必須能夠感覺到失敗的操作, 進行log(用于事後人工進行補償性事務操作或者交由中間件接管在之後進行補償性事務操作).

優點

對比與前面提到的兩階段送出法, 有兩大優勢:

  • TCC能夠對分布式事務中的各個資源進行分别鎖定, 分别送出與釋放, 例如, 假設有AB兩個操作, 假設A操作耗時短, 那麼A就能較快的完成自身的try-confirm-cancel流程, 釋放資源. 無需等待B操作. 如果事後出現問題, 追加執行補償性事務即可.
  • TCC是綁定在各個子業務上的(除了cancle中的全局復原操作), 也就是各服務之間可以在一定程度上”異步并行”執行.

注意事項

  • 事務管理器(協調器)這個節點必須以帶同步複制語義的高可用叢集(HAC)方式部署.
  • 事務管理器(協調器)還需要使用多數派算法來避免叢集發生腦裂問題.

适用場景

  • 嚴格一緻性
  • 執行時間短
  • 實時性要求高

舉例: 紅包, 收付款業務.

異步確定型

通過将一系列同步的事務操作變為基于消息執行的異步操作, 避免了分布式事務中的同步阻塞操作的影響.

這個方案真正實作了兩個服務的解耦, 解耦的關鍵就是異步消息和補償性事務.

這裡以一個例子作為講解:

微服務--分布式事務的實作方法及替代方案

執行步驟如下:

  1. MQ發送方發送遠端事務消息到MQ Server;
  2. MQ Server給予響應, 表明事務消息已成功到達MQ Server.
  3. MQ發送方Commit本地事務.
  4. 若本地事務Commit成功, 則通知MQ Server允許對應事務消息被消費; 若本地事務失敗, 則通知MQ Server對應事務消息應被丢棄.
  5. 若MQ發送方逾時未對MQ Server作出本地事務執行狀态的回報, 那麼需要MQ Servfer向MQ發送方主動回查事務狀态, 以決定事務消息是否能被消費.
  6. 當得知本地事務執行成功時, MQ Server允許MQ訂閱方消費本條事務消息.

需要額外說明的一點, 就是事務消息投遞到MQ訂閱方後, 并不一定能夠成功執行. 需要MQ訂閱方主動給予消費回報(ack)

  • 如果MQ訂閱方執行遠端事務成功, 則給予消費成功的ack, 那麼MQ Server可以安全将事務消息移除;
  • 如果執行失敗, MQ Server需要對消息重新投遞, 直至消費成功.

  • 消息中間件在系統中扮演一個重要的角色, 所有的事務消息都需要通過它來傳達, 是以消息中間件也需要支援 HAC 來確定事務消息不丢失.
  • 根據業務邏輯的具體實作不同,還可能需要對消息中間件增加消息不重複, 不亂序等其它要求.

  • 執行周期較長
  • 實時性要求不高

例如:

  • 跨行轉賬/彙款業務(兩個服務分别在不同的銀行中)
  • 退貨/退款業務
  • 财務, 賬單統計業務(先發送到消息中間件, 然後進行批量記賬)

最大努力通知型

這是分布式事務中要求最低的一種, 也可以通過消息中間件實作, 與前面異步確定型操作不同的一點是, 在消息由MQ Server投遞到消費者之後, 允許在達到最大重試次數之後正常結束事務.

交易結果消息的通知等.

小結

不管是同步事務中的事務管理器(協調者), 還是異步事務中使用的消息中間件,若要達到一緻性保證,都需要使用帶有同步複制語義的 HAC 提供的高可用和高可靠特性,這些都是以性能為代價的,無疑成為了SOA 架構中的典型性能瓶頸之一.