天天看點

微服務間保持事務一緻性

問題:

有一個請求去調用了服務A,A中需要向資料庫寫入資料,其中A裡面又調用了服務B,B中也向伺服器寫入了一些資料,當A成功調用B之後,B正常執行了,A的操作發生了異常,A操作的資料可以正常復原,那麼問題是B服務的事務如何與A保持一緻呢?

解決方案:

服務A與服務B屬于不同的應用,通過dubbo遠端調用,要做到二者寫庫操作一同送出/一同復原,服務A和服務B必須參與同一個跨應用的全局事務,并保證二者對應的DB事務必須作為該全局事務的分支事務。這樣,事務管理子產品在明确了該全局事務的完成方向(commit/rollback)後,再将該全局事務下的所有分支事務逐個送出/復原。

這是分布式事務管理的大緻邏輯,其中,上述“将所有分支事務逐個送出/復原”過程是分布式事務處理的關鍵,需要有相應故障恢複的機制,例如,當服務A的DB事務已經送出(服務B的DB事務尚未送出)時,若服務B所在節點當機(或其使用的DB當機)時,如何保證服務B的DB事務仍能正常送出。這個過程的實作機制有很多種,常見的有XA 2PC和TCC。

XA機制将送出過程分成prepare、commit兩個階段,事務管理子產品在prepare服務A的DB事務、服務B的DB事務都成功後,再逐個commit這些DB事務。DB在prepare傳回OK後,如果沒有收到來自事務管理子產品的commit/rollback請求則會一直保留該分支事務的資料。是以,若上述當機故障出現在prepare階段,則可以通過将prepare過的分支事務復原,來達到全局事務復原;若上述當機故障出現在commit階段,後續仍然可以再次commit那些未成功commit的分支事務,最終達到全局事務送出。

TCC機制下,事務管理子產品是在服務A、服務B執行完畢後即刻送出其參與的DB事務。而後,如果全局事務決定送出,則逐個調用服務A和服務B的confirm邏輯;如果全局事務決定復原,則逐個調用服務A和服務B的cancel邏輯(當然,confirm/cancel邏輯的執行中又會參與相應的DB事務)。若發生上述當機故障,則隻需要根據全局事務目前狀态,将服務A、服務B相應的confirm/cancel邏輯重新調用即可。因confirm/cancel邏輯可能會被多次調用,是以,需要保證其幂等性。

知名的分布式事務管理器主要有atomikos、bitronix、narayana。其中,僅atomikos支援XA和TCC兩種機制,bitronix、narayana僅支援XA機制。這三者都不提供對dubbo的開箱即用的支援,需要自行內建。

目前對dubbo提供開箱即用支援的分布式事務管理器有:ByteJTA(基于XA機制)、ByteTCC(基于TCC機制)。

目前比較多的解決方案有幾個: 一、結合MQ消息中間件實作的可靠消息最終一緻性 二、TCC補償性事務解決方案 三、最大努力通知型方案 第一種方案:可靠消息最終一緻性,需要業務系統結合MQ消息中間件實作,在實作過程中需要保證消息的成功發送及成功消費。即需要通過業務系統控制MQ的消息狀态 第二種方案:TCC補償性,分為三個階段TRYING-CONFIRMING-CANCELING。每個階段做不同的處理。TRYING階段主要是對業務系統進行檢測及資源預留 CONFIRMING階段是做業務送出,通過TRYING階段執行成功後,再執行該階段。預設如果TRYING階段執行成功,CONFIRMING就一定能成功。CANCELING階段是回對業務做復原,在TRYING階段中,如果存在分支事務TRYING失敗,則需要調用CANCELING将已預留的資源進行釋放。第三種方案:最大努力通知xing型,這種方案主要用在與第三方系統通訊時,比如:調用微信或支付寶支付後的支付結果通知。這種方案也是結合MQ進行實作,例如:通過MQ發送http請求,設定最大通知次數。達到通知次數後即不再通知。

其他解決方案:首先,要明确 需不需要保證資料的一緻性,有些業務場景 就不需要一緻性。

而你的既然需要,復原機制,讓對方的服務提供復原接口,調用方假設調用接口出錯,本地的東西 通過本地事物 能復原,而外部系統 你catch了這個Exception,則要調用它的復原接口。