分佈式事務常用解決方案

常見解決方案

  1. 分佈式事物解決方案 可以使用全局事物2pc(兩段提交協議)、3pc(三段提交協議),tcc補償機制、提供回滾接口、分佈式數據庫
  2. LCN 核心採用3PC+TCC補償機制

 

什麼XA接口 

XA–eXtended Architecture 在事務中意爲分佈式事務 
XA由協調者(coordinator,一般爲transaction manager)和參與者(participants,一般在各個資源上有各自的resource manager)共同完成。在MySQL中,XA事務有兩種。

什麼JTA

作爲java平臺上事務規範JTA(Java Transaction API)也定義了對XA事務的支持,實際上,JTA是基於XA架構上建模的,在JTA 中,事務管理器抽象爲javax.transaction.TransactionManager接口,並通過底層事務服務(即JTS)實現。像很多其他的java規範一樣,JTA僅僅定義了接口,具體的實現則是由供應商(如J2EE廠商)負責提供,目前JTA的實現主要由以下幾種:


1.J2EE容器所提供的JTA實現(JBoss)
2.獨立的JTA實現:如JOTM,Atomikos.這些實現可以應用在那些不使用J2EE應用服務器的環境裏用以提供分佈事事務保證。如Tomcat,Jetty以及普通的java應用。

 

2PC兩段提交

所謂的兩個階段是指:第一階段:準備階段(投票階段)和第二階段:提交階段(執行階段)

XA一般由兩階段完成,稱爲two-phase commit(2PC)。 
階段一爲準備階段,即所有的參與者準備執行事務並鎖住需要的資源。參與者ready時,向transaction manager彙報自己已經準備好。 
階段二爲提交階段。當transaction manager確認所有參與者都ready後,向所有參與者發送commit命令。 
如下圖所示: 

 

XA的性能問題 
XA的性能很低。一個數據庫的事務和多個數據庫間的XA事務性能對比可發現,性能差10倍左右。因此要儘量避免XA事務,例如可以將數據寫入本地,用高性能的消息系統分發數據。或使用數據庫複製等技術。 
只有在這些都無法實現,且性能不是瓶頸時才應該使用XA。

 

3PC三段提交

三階段提交(Three-phase commit),也叫三階段提交協議(Three-phase commit protocol),是二階段提交(2PC)的改進版本。

 

與兩階段提交不同的是,三階段提交有兩個改動點。

1、引入超時機制。同時在協調者和參與者中都引入超時機制。
2、在第一階段和第二階段中插入一個準備階段。保證了在最後提交階段之前各參與節點的狀態是一致的。

也就是說,除了引入超時機制之外,3PC把2PC的準備階段再次一分爲二,這樣三階段提交就有CanCommit、PreCommit、DoCommit三個階段。

CanCommit階段

3PC的CanCommit階段其實和2PC的準備階段很像。協調者向參與者發送commit請求,參與者如果可以提交就返回Yes響應,否則返回No響應。

1.事務詢問 協調者向參與者發送CanCommit請求。詢問是否可以執行事務提交操作。然後開始等待參與者的響應。

2.響應反饋 參與者接到CanCommit請求之後,正常情況下,如果其自身認爲可以順利執行事務,則返回Yes響應,並進入預備狀態。否則反饋No

PreCommit階段

協調者根據參與者的反應情況來決定是否可以記性事務的PreCommit操作。根據響應情況,有以下兩種可能。

假如協調者從所有的參與者獲得的反饋都是Yes響應,那麼就會執行事務的預執行。

1.發送預提交請求 協調者向參與者發送PreCommit請求,並進入Prepared階段。

2.事務預提交 參與者接收到PreCommit請求後,會執行事務操作,並將undo和redo信息記錄到事務日誌中。

3.響應反饋 如果參與者成功的執行了事務操作,則返回ACK響應,同時開始等待最終指令。

假如有任何一個參與者向協調者發送了No響應,或者等待超時之後,協調者都沒有接到參與者的響應,那麼就執行事務的中斷。

1.發送中斷請求 協調者向所有參與者發送abort請求。

2.中斷事務 參與者收到來自協調者的abort請求之後(或超時之後,仍未收到協調者的請求),執行事務的中斷。

doCommit階段

該階段進行真正的事務提交,也可以分爲以下兩種情況。

執行提交

1.發送提交請求 協調接收到參與者發送的ACK響應,那麼他將從預提交狀態進入到提交狀態。並向所有參與者發送doCommit請求。

2.事務提交 參與者接收到doCommit請求之後,執行正式的事務提交。並在完成事務提交之後釋放所有事務資源。

3.響應反饋 事務提交完之後,向協調者發送Ack響應。

4.完成事務 協調者接收到所有參與者的ack響應之後,完成事務。

中斷事務 協調者沒有接收到參與者發送的ACK響應(可能是接受者發送的不是ACK響應,也可能響應超時),那麼就會執行中斷事務。

1.發送中斷請求 協調者向所有參與者發送abort請求

2.事務回滾 參與者接收到abort請求之後,利用其在階段二記錄的undo信息來執行事務的回滾操作,並在完成回滾之後釋放所有的事務資源。

3.反饋結果 參與者完成事務回滾之後,向協調者發送ACK消息

4.中斷事務 協調者接收到參與者反饋的ACK消息之後,執行事務的中斷。

在doCommit階段,如果參與者無法及時接收到來自協調者的doCommit或者rebort請求時,會在等待超時之後,會繼續進行事務的提交。(其實這個應該是基於概率來決定的,當進入第三階段時,說明參與者在第二階段已經收到了PreCommit請求,那麼協調者產生PreCommit請求的前提條件是他在第二階段開始之前,收到所有參與者的CanCommit響應都是Yes。(一旦參與者收到了PreCommit,意味他知道大家其實都同意修改了)所以,一句話概括就是,當進入第三階段時,由於網絡超時等原因,雖然參與者沒有收到commit或者abort響應,但是他有理由相信:成功提交的機率很大。 )

2PC與3PC的區別

相對於2PC,3PC主要解決的單點故障問題,並減少阻塞,因爲一旦參與者無法及時收到來自協調者的信息之後,他會默認執行commit。而不會一直持有事務資源並處於阻塞狀態。但是這種機制也會導致數據一致性問題,因爲,由於網絡原因,協調者發送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時之後執行了commit操作。這樣就和其他接到abort命令並執行回滾的參與者之間存在數據不一致的情況。

TCC

TRYING 階段主要是對業務系統做檢測及資源預留

CONFIRMING 階段主要是對業務系統做確認提交,TRYING階段執行成功並開始執行CONFIRMING階段時,默認                                      CONFIRMING階段是不會出錯的。即:只要TRYING成功,CONFIRMING一定成功。

CANCELING 階段主要是在業務執行錯誤,需要回滾的狀態下執行的業務取消,預留資源釋放。

而冪等性則是指業務方法調用一次與調用多次的執行返回結果是一樣的。

舉個支付項目的例子:

 

支付系統接收到會員的支付請求後,需要扣減會員賬戶餘額、增加會員積分(暫時假設需要同步實現)增加商戶賬戶餘額

再假設:會員系統、商戶系統、積分系統是獨立的三個子系統,無法通過傳統的事務方式進行處理。

TRYING階段:我們需要做的就是會員資金賬戶的資金預留,即:凍結會員賬戶的金額(訂單金額)

CONFIRMING階段:我們需要做的就是會員積分賬戶增加積分餘額,商戶賬戶增加賬戶餘額

CANCELING階段:該階段需要執行的就是解凍釋放我們扣減的會員餘額

MQ分佈式事物

 採用時效性高的 MQ,由對方訂閱消息並監聽,有消息時自動觸發事件
採用定時輪詢掃描的方式,去檢查消息表的數據。

其他補償

做過支付寶交易接口的同學都知道,我們一般會在支付寶的回調頁面和接口裏,解密參數,然後調用系統中更新交易狀態相關的服務,將訂單更新爲付款成功。同時,只有當我們回調頁面中輸出了 success 字樣或者標識業務處理成功相應狀態碼時,支付寶纔會停止回調請求。否則,支付寶會每間隔一段時間後,再向客戶方發起回調請求,直到輸出成功標識爲止。
其實這就是一個很典型的補償例子,跟一些 MQ 重試補償機制很類似。

一般成熟的系統中,對於級別較高的服務和接口,整體的可用性通常都會很高。如果有些業務由於瞬時的網絡故障或調用超時等問題,那麼這種重試機制其實是非常有效的。

當然,考慮個比較極端的場景,假如系統自身有 bug 或者程序邏輯有問題,那麼重試 1W 次那也是無濟於事的。那豈不是就發生了“明明已經付款,卻顯示未付款不發貨”類似的悲劇?

其實爲了交易系統更可靠,我們一般會在類似交易這種高級別的服務代碼中,加入詳細日誌記錄的,一旦系統內部引發類似致命異常,會有郵件通知。同時,後臺會有定時任務掃描和分析此類日誌,檢查出這種特殊的情況,會嘗試通過程序來補償並郵件通知相關人員。

在某些特殊的情況下,還會有“人工補償”的,這也是最後一道屏障。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章