七种常见分布式事务详解(2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通知)
分布式事務(wù):在分布式系統(tǒng)中一次操作需要由多個服務(wù)協(xié)同完成,這種由不同的服務(wù)之間通過網(wǎng)絡(luò)協(xié)同完成的事務(wù)稱為分布式事務(wù)
一、2PC:
????????2PC,兩階段提交,將事務(wù)的提交過程分為資源準備和資源提交兩個階段,并且由事務(wù)協(xié)調(diào)者來協(xié)調(diào)所有事務(wù)參與者,如果準備階段所有事務(wù)參與者都預(yù)留資源成功,則進行第二階段的資源提交,否則事務(wù)協(xié)調(diào)者回滾資源。
1、第一階段:準備階段
由事務(wù)協(xié)調(diào)者詢問通知各個事務(wù)參與者,是否準備好了執(zhí)行事務(wù),具體流程圖如下:
- ① 協(xié)調(diào)者向所有參與者發(fā)送事務(wù)內(nèi)容,詢問是否可以提交事務(wù),并等待答復(fù)
- ② 各參與者執(zhí)行本地事務(wù)操作,將 undo 和 redo 信息記入事務(wù)日志中(但不提交事務(wù))
- ③ 如參與者執(zhí)行成功,給協(xié)調(diào)者反饋同意,否則反饋中止,表示事務(wù)不可以執(zhí)行
2、第二階段:提交階段
????????協(xié)調(diào)者收到各個參與者的準備消息后,根據(jù)反饋情況通知各個參與者commit提交或者rollback回滾
(1)事務(wù)提交:
????????當(dāng)?shù)谝浑A段所有參與者都反饋同意時,協(xié)調(diào)者發(fā)起正式提交事務(wù)的請求,當(dāng)所有參與者都回復(fù)同意時,則意味著完成事務(wù),具體流程如下:
- ① 協(xié)調(diào)者節(jié)點向所有參與者節(jié)點發(fā)出正式提交的 commit 請求。
- ② 收到協(xié)調(diào)者的 commit 請求后,參與者正式執(zhí)行事務(wù)提交操作,并釋放在整個事務(wù)期間內(nèi)占用的資源。
- ③ 參與者完成事務(wù)提交后,向協(xié)調(diào)者節(jié)點發(fā)送ACK消息。
- ④ 協(xié)調(diào)者節(jié)點收到所有參與者節(jié)點反饋的ACK消息后,完成事務(wù)。
所以,正常提交時,事務(wù)的完整流程圖如下:
?(2)事務(wù)回滾:
如果任意一個參與者節(jié)點在第一階段返回的消息為中止,或者協(xié)調(diào)者節(jié)點在第一階段的詢問超時之前無法獲取所有參與者節(jié)點的響應(yīng)消息時,那么這個事務(wù)將會被回滾,具體流程如下:
- ① 協(xié)調(diào)者向所有參與者發(fā)出 rollback 回滾操作的請求
- ② 參與者利用階段一寫入的undo信息執(zhí)行回滾,并釋放在整個事務(wù)期間內(nèi)占用的資源
- ③ 參與者在完成事務(wù)回滾之后,向協(xié)調(diào)者發(fā)送回滾完成的ACK消息
- ④ 協(xié)調(diào)者收到所有參與者反饋的ACK消息后,取消事務(wù)
所以,事務(wù)回滾時,完整流程圖如下:
?3、2PC的缺點:
二階段提交確實能夠提供原子性的操作,但是不幸的是,二階段提交還是有幾個缺點的:
(1)性能問題:執(zhí)行過程中,所有參與節(jié)點都是事務(wù)阻塞性的,當(dāng)參與者占有公共資源時,其他第三方節(jié)點訪問公共資源就不得不處于阻塞狀態(tài),為了數(shù)據(jù)的一致性而犧牲了可用性,對性能影響較大,不適合高并發(fā)高性能場景
(2)可靠性問題:2PC非常依賴協(xié)調(diào)者,當(dāng)協(xié)調(diào)者發(fā)生故障時,尤其是第二階段,那么所有的參與者就會都處于鎖定事務(wù)資源的狀態(tài)中,而無法繼續(xù)完成事務(wù)操作(如果是協(xié)調(diào)者掛掉,可以重新選舉一個協(xié)調(diào)者,但是無法解決因為協(xié)調(diào)者宕機導(dǎo)致的參與者處于阻塞狀態(tài)的問題)
(3)數(shù)據(jù)一致性問題:在階段二中,當(dāng)協(xié)調(diào)者向參與者發(fā)送commit請求之后,發(fā)生了局部網(wǎng)絡(luò)異常或者在發(fā)送commit請求過程中協(xié)調(diào)者發(fā)生了故障,這回導(dǎo)致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之后就會執(zhí)行commit操作。但是其他部分未接到commit請求的機器則無法執(zhí)行事務(wù)提交。于是整個分布式系統(tǒng)便出現(xiàn)了數(shù)據(jù)部一致性的現(xiàn)象。
(4)二階段無法解決的問題:協(xié)調(diào)者在發(fā)出 commit 消息之后宕機,而唯一接收到這條消息的參與者同時也宕機了,那么即使協(xié)調(diào)者通過選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者,這條事務(wù)的狀態(tài)也是不確定的,沒人知道事務(wù)是否被已經(jīng)提交。
二、3PC:
????????3PC,三階段提交協(xié)議,是二階段提交協(xié)議的改進版本,三階段提交有兩個改動點:
- (1)在協(xié)調(diào)者和參與者中都引入超時機制
- (2)在第一階段和第二階段中插入一個準備階段,保證了在最后提交階段之前各參與節(jié)點的狀態(tài)是一致的。
????????所以3PC會分為3個階段,CanCommit 準備階段、PreCommit 預(yù)提交階段、DoCommit 提交階段,處理流程如下:
?1、階段一:CanCommit 準備階段
????????協(xié)調(diào)者向參與者發(fā)送 canCommit 請求,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng),具體流程如下:
- (1)事務(wù)詢問:協(xié)調(diào)者向所有參與者發(fā)出包含事務(wù)內(nèi)容的 canCommit 請求,詢問是否可以提交事務(wù),并等待所有參與者答復(fù)。
- (2)響應(yīng)反饋:參與者收到 canCommit 請求后,如果認為可以執(zhí)行事務(wù)操作,則反饋 yes 并進入預(yù)備狀態(tài),否則反饋 no。
2、階段二:PreCommit 階段
????????協(xié)調(diào)者根據(jù)參與者的反應(yīng)情況來決定是否可以進行事務(wù)的 PreCommit 操作。根據(jù)響應(yīng)情況,有以下兩種可能:
(1)執(zhí)行事務(wù):
假如所有參與者均反饋 yes,協(xié)調(diào)者預(yù)執(zhí)行事務(wù),具體如下:
- ① 發(fā)送預(yù)提交請求:協(xié)調(diào)者向參與者發(fā)送 PreCommit 請求,并進入準備階段
- ② 事務(wù)預(yù)提交 :參與者接收到 PreCommit 請求后,會執(zhí)行本地事務(wù)操作,并將 undo 和 redo 信息記錄到事務(wù)日志中(但不提交事務(wù))
- ③ 響應(yīng)反饋 :如果參與者成功的執(zhí)行了事務(wù)操作,則返回ACK響應(yīng),同時開始等待最終指令。
?(2)中斷事務(wù):
假如有任何一個參與者向協(xié)調(diào)者發(fā)送了No響應(yīng),或者等待超時之后,協(xié)調(diào)者都沒有接到參與者的響應(yīng),那么就執(zhí)行事務(wù)的中斷,流程如下:
- ① 發(fā)送中斷請求 :協(xié)調(diào)者向所有參與者發(fā)送 abort 請求。
- ② 中斷事務(wù) :參與者收到來自協(xié)調(diào)者的 abort 請求之后(或超時之后,仍未收到協(xié)調(diào)者的請求),執(zhí)行事務(wù)的中斷。
3、階段三:doCommit階段
該階段進行真正的事務(wù)提交,也可以分為以下兩種情況:
(1)提交事務(wù):
- ① 發(fā)送提交請求:協(xié)調(diào)接收到所有參與者發(fā)送的ACK響應(yīng),那么他將從預(yù)提交狀態(tài)進入到提交狀態(tài),并向所有參與者發(fā)送 doCommit 請求
- ② 本地事務(wù)提交:參與者接收到doCommit請求之后,執(zhí)行正式的事務(wù)提交,并在完成事務(wù)提交之后釋放所有事務(wù)資源
- ③ 響應(yīng)反饋:事務(wù)提交完之后,向協(xié)調(diào)者發(fā)送ack響應(yīng)。
- ④ 完成事務(wù):協(xié)調(diào)者接收到所有參與者的ack響應(yīng)之后,完成事務(wù)。
(2)中斷事務(wù):任何一個參與者反饋 no,或者等待超時后協(xié)調(diào)者尚無法收到所有參與者的反饋,即中斷事務(wù)
- ① 發(fā)送中斷請求:如果協(xié)調(diào)者處于工作狀態(tài),向所有參與者發(fā)出 abort 請求
- ② 事務(wù)回滾:參與者接收到abort請求之后,利用其在階段二記錄的undo信息來執(zhí)行事務(wù)的回滾操作,并在完成回滾之后釋放所有的事務(wù)資源。
- ③ 反饋結(jié)果:參與者完成事務(wù)回滾之后,向協(xié)調(diào)者反饋ACK消息
- ④ 中斷事務(wù):協(xié)調(diào)者接收到參與者反饋的ACK消息之后,執(zhí)行事務(wù)的中斷。
????????進入doCommit階段后,無論協(xié)調(diào)者出現(xiàn)問題,或者協(xié)調(diào)者與參與者之間的網(wǎng)絡(luò)出現(xiàn)問題,都會導(dǎo)致參與者無法接收到協(xié)調(diào)者發(fā)出的 doCommit 請求或 abort 請求。此時,參與者都會在等待超時之后,繼續(xù)執(zhí)行事務(wù)提交。這其實基于概率來決定的,當(dāng)進入第三階段時,說明第一階段收到所有參與者的CanCommit響應(yīng)都是Yes,意味著大家都同意修改了,并且第二階段所有的參與者對協(xié)調(diào)者的PreCommit請求也都是同意的。所以,一句話概括就是,當(dāng)進入第三階段時,由于網(wǎng)絡(luò)超時等原因,雖然參與者沒有收到commit或者abort響應(yīng),但是他有理由相信:成功提交的幾率很大。
4、3PC的優(yōu)缺點:
????????與2PC相比,3PC降低了阻塞范圍,并且在等待超時后,協(xié)調(diào)者或參與者會中斷事務(wù),避免了協(xié)調(diào)者單點問題,階段三中協(xié)調(diào)者出現(xiàn)問題時,參與者會繼續(xù)提交事務(wù)。
????????數(shù)據(jù)不一致問題依然存在,當(dāng)在參與者收到 preCommit 請求后等待 doCommit 指令時,此時如果協(xié)調(diào)者請求中斷事務(wù),而協(xié)調(diào)者因為網(wǎng)絡(luò)問題無法與參與者正常通信,會導(dǎo)致參與者繼續(xù)提交事務(wù),造成數(shù)據(jù)不一致。
2PC和3PC都無法保證數(shù)據(jù)絕對的一致性,一般為了預(yù)防這種問題,可以添加一個報警,比如監(jiān)控到事務(wù)異常的時候,通過腳本自動補償差異的信息。
三、TCC:
1、什么是TCC:
????????TCC(Try Confirm Cancel)是應(yīng)用層的兩階段提交,所以對代碼的侵入性強,其核心思想是:針對每個操作,都要實現(xiàn)對應(yīng)的確認和補償操作,也就是業(yè)務(wù)邏輯的每個分支都需要實現(xiàn) try、confirm、cancel 三個操作,第一階段由業(yè)務(wù)代碼編排來調(diào)用Try接口進行資源預(yù)留,當(dāng)所有參與者的 Try 接口都成功了,事務(wù)協(xié)調(diào)者提交事務(wù),并調(diào)用參與者的 confirm 接口真正提交業(yè)務(wù)操作,否則調(diào)用每個參與者的 cancel 接口回滾事務(wù),并且由于 confirm 或者 cancel 有可能會重試,因此對應(yīng)的部分需要支持冪等。
2、TCC的執(zhí)行流程:
????????TCC的執(zhí)行流程可以分為兩個階段,分別如下:
(1)第一階段:Try,業(yè)務(wù)系統(tǒng)做檢測并預(yù)留資源 (加鎖,鎖住資源),比如常見的下單,在try階段,我們不是真正的減庫存,而是把下單的庫存給鎖定住。
(2)第二階段:根據(jù)第一階段的結(jié)果決定是執(zhí)行confirm還是cancel
- Confirm:執(zhí)行真正的業(yè)務(wù)(執(zhí)行業(yè)務(wù),釋放鎖)
- Cancle:是對Try階段預(yù)留資源的釋放(出問題,釋放鎖)
?3、TCC如何保證最終一致性:
- TCC 事務(wù)機制以 Try 為中心的,Confirm 確認操作和 Cancel 取消操作都是圍繞 Try 而展開。因此,Try 階段中的操作,其保障性是最好的,即使失敗,仍然有 Cancel 取消操作可以將其執(zhí)行結(jié)果撤銷。
- Try階段執(zhí)行成功并開始執(zhí)行 Confirm 階段時,默認 Confirm 階段是不會出錯的,也就是說只要 Try 成功,Confirm 一定成功(TCC設(shè)計之初的定義)
- Confirm 與 Cancel 如果失敗,由TCC框架進行重試補償
- 存在極低概率在CC環(huán)節(jié)徹底失敗,則需要定時任務(wù)或人工介入
4、TCC的注意事項:
(1)允許空回滾:
????????空回滾出現(xiàn)的原因是 Try 超時或者丟包,導(dǎo)致 TCC 分布式事務(wù)二階段的 回滾,觸發(fā) Cancel 操作,此時事務(wù)參與者未收到Try,但是卻收到了Cancel 請求,如下圖所示:
????????所以 cancel 接口在實現(xiàn)時需要允許空回滾,也就是 Cancel 執(zhí)行時如果發(fā)現(xiàn)沒有對應(yīng)的事務(wù) xid 或主鍵時,需要返回回滾成功,讓事務(wù)服務(wù)管理器認為已回滾。
(2)防懸掛控制:
????????懸掛指的是二階段的 Cancel 比 一階段的Try 操作先執(zhí)行,出現(xiàn)該問題的原因是 Try 由于網(wǎng)絡(luò)擁堵而超時,導(dǎo)致事務(wù)管理器生成回滾,觸發(fā) Cancel 接口,但之后擁堵在網(wǎng)絡(luò)的 Try 操作又被資源管理器收到了,但是 Cancel 比 Try 先到。但按照前面允許空回滾的邏輯,回滾會返回成功,事務(wù)管理器認為事務(wù)已回滾成功,所以此時應(yīng)該拒絕執(zhí)行空回滾之后到來的 Try 操作,否則會產(chǎn)生數(shù)據(jù)不一致。因此我們可以在 Cancel 空回滾返回成功之前,先記錄該條事務(wù) xid 或業(yè)務(wù)主鍵,標識這條記錄已經(jīng)回滾過,Try 接口執(zhí)行前先檢查這條事務(wù)xid或業(yè)務(wù)主鍵是否已經(jīng)標記為回滾成功,如果是則不執(zhí)行 Try 的業(yè)務(wù)操作。
?(3)冪等控制:
????????由于網(wǎng)絡(luò)原因或者重試操作都有可能導(dǎo)致 Try - Confirm - Cancel 3個操作的重復(fù)執(zhí)行,所以使用 TCC 時需要注意這三個操作的冪等控制,通常我們可以使用事務(wù) xid 或業(yè)務(wù)主鍵判重來控制。
5、TCC方案的優(yōu)缺點:
(1)TCC 事務(wù)機制相比于上面介紹的 XA 事務(wù)機制,有以下優(yōu)點:
- 性能提升:具體業(yè)務(wù)來實現(xiàn),控制資源鎖的粒度變小,不會鎖定整個資源。
- 數(shù)據(jù)最終一致性:基于 Confirm 和 Cancel 的冪等性,保證事務(wù)最終完成確認或者取消,保證數(shù)據(jù)的一致性。
- 可靠性:解決了 XA 協(xié)議的協(xié)調(diào)者單點故障問題,由主業(yè)務(wù)方發(fā)起并控制整個業(yè)務(wù)活動,業(yè)務(wù)活動管理器也變成多點,引入集群。
(2)缺點:TCC 的 Try、Confirm 和 Cancel 操作功能要按具體業(yè)務(wù)來實現(xiàn),業(yè)務(wù)耦合度較高,提高了開發(fā)成本。
四、Saga事務(wù):
1、什么是Saga事務(wù):
????????Saga 事務(wù)核心思想是將長事務(wù)拆分為多個本地短事務(wù)并依次正常提交,如果所有短事務(wù)均執(zhí)行成功,那么分布式事務(wù)提交;如果出現(xiàn)某個參與者執(zhí)行本地事務(wù)失敗,則由 Saga 事務(wù)協(xié)調(diào)器協(xié)調(diào)根據(jù)相反順序調(diào)用補償操作,回滾已提交的參與者,使分布式事務(wù)回到最初始的狀態(tài)。Saga 事務(wù)基本協(xié)議如下:
- (1)每個 Saga 事務(wù)由一系列冪等的有序子事務(wù)(sub-transaction) Ti 組成。
- (2)每個 Ti 都有對應(yīng)的冪等補償動作 Ci,補償動作用于撤銷 Ti 造成的結(jié)果。
????????與TCC事務(wù)補償機制相比,TCC有一個預(yù)留(Try)動作,相當(dāng)于先報存一個草稿,然后才提交;Saga事務(wù)沒有預(yù)留動作,直接提交。
2、Saga的恢復(fù)策略:
對于事務(wù)異常,Saga提供了兩種恢復(fù)策略,分別如下:
(1)向后恢復(fù)(backward recovery):
當(dāng)執(zhí)行事務(wù)失敗時,補償所有已完成的事務(wù),是“一退到底”的方式,這種做法的效果是撤銷掉之前所有成功的子事務(wù),使得整個 Saga 的執(zhí)行結(jié)果撤銷。如下圖:
?????????從上圖可知事務(wù)執(zhí)行到了支付事務(wù)T3,但是失敗了,因此事務(wù)回滾需要從C3,C2,C1依次進行回滾補償,對應(yīng)的執(zhí)行順序為:T1,T2,T3,C3,C2,C1。
(2)向前恢復(fù)(forward recovery):
????????對于執(zhí)行不通過的事務(wù),會嘗試重試事務(wù),這里有一個假設(shè)就是每個子事務(wù)最終都會成功,這種方式適用于必須要成功的場景,事務(wù)失敗了重試,不需要補償。流程如下圖:
?3、Saga事務(wù)的實現(xiàn)方式:
Saga事務(wù)有兩種不同的實現(xiàn)方式,分別如下:
- 命令協(xié)調(diào)(Order Orchestrator)
- 事件編排(Event Choreographyo)
(1)命令協(xié)調(diào):
????????中央?yún)f(xié)調(diào)器(Orchestrator,簡稱 OSO)以命令/回復(fù)的方式與每項服務(wù)進行通信,全權(quán)負責(zé)告訴每個參與者該做什么以及什么時候該做什么。整體流程如下圖:
- ① 事務(wù)發(fā)起方的主業(yè)務(wù)邏輯請求 OSO 服務(wù)開啟訂單事務(wù)
- ② OSO 向庫存服務(wù)請求扣減庫存,庫存服務(wù)回復(fù)處理結(jié)果。
- ③ OSO 向訂單服務(wù)請求創(chuàng)建訂單,訂單服務(wù)回復(fù)創(chuàng)建結(jié)果。
- ④ OSO 向支付服務(wù)請求支付,支付服務(wù)回復(fù)處理結(jié)果。
- ⑤ 主業(yè)務(wù)邏輯接收并處理 OSO 事務(wù)處理結(jié)果回復(fù)。
????????中央?yún)f(xié)調(diào)器 OSO 必須事先知道執(zhí)行整個事務(wù)所需的流程,如果有任何失敗,它還負責(zé)通過向每個參與者發(fā)送命令來撤銷之前的操作來協(xié)調(diào)分布式的回滾,基于中央?yún)f(xié)調(diào)器協(xié)調(diào)一切時,回滾要容易得多,因為協(xié)調(diào)器默認是執(zhí)行正向流程,回滾時只要執(zhí)行反向流程即可。
(2)事件編排:
????????命令協(xié)調(diào)方式基于中央?yún)f(xié)調(diào)器實現(xiàn),所以有單點風(fēng)險,但是事件編排方式?jīng)]有中央?yún)f(xié)調(diào)器。事件編排的實現(xiàn)方式中,每個服務(wù)產(chǎn)生自己的時間并監(jiān)聽其他服務(wù)的事件來決定是否應(yīng)采取行動。
????????在事件編排方法中,第一個服務(wù)執(zhí)行一個事務(wù),然后發(fā)布一個事件,該事件被一個或多個服務(wù)進行監(jiān)聽,這些服務(wù)再執(zhí)行本地事務(wù)并發(fā)布(或不發(fā)布)新的事件。當(dāng)最后一個服務(wù)執(zhí)行本地事務(wù)并且不發(fā)布任何事件時,意味著分布式事務(wù)結(jié)束,或者它發(fā)布的事件沒有被任何 Saga 參與者聽到都意味著事務(wù)結(jié)束。
- ① 事務(wù)發(fā)起方的主業(yè)務(wù)邏輯發(fā)布開始訂單事件。
- ② 庫存服務(wù)監(jiān)聽開始訂單事件,扣減庫存,并發(fā)布庫存已扣減事件。
- ③ 訂單服務(wù)監(jiān)聽庫存已扣減事件,創(chuàng)建訂單,并發(fā)布訂單已創(chuàng)建事件。
- ④ 支付服務(wù)監(jiān)聽訂單已創(chuàng)建事件,進行支付,并發(fā)布訂單已支付事件。
- ⑤ 主業(yè)務(wù)邏輯監(jiān)聽訂單已支付事件并處理。
????????如果事務(wù)涉及 2 至 4 個步驟,則非常合適使用事件編排方式,它是實現(xiàn) Saga 模式的自然方式,它很簡單,容易理解,不需要太多的代碼來構(gòu)建。
4、Saga事務(wù)的優(yōu)缺點:
(1)命令協(xié)調(diào)設(shè)計的優(yōu)缺點:
① 優(yōu)點:
- 服務(wù)之間關(guān)系簡單,避免服務(wù)間循環(huán)依賴,因為 Saga 協(xié)調(diào)器會調(diào)用 Saga 參與者,但參與者不會調(diào)用協(xié)調(diào)器。
- 程序開發(fā)簡單,只需要執(zhí)行命令/回復(fù)(其實回復(fù)消息也是一種事件消息),降低參與者的復(fù)雜性。
- 易維護擴展,在添加新步驟時,事務(wù)復(fù)雜性保持線性,回滾更容易管理,更容易實施和測試。
② 缺點:
- 中央?yún)f(xié)調(diào)器處理邏輯容易變得龐大復(fù)雜,導(dǎo)致難以維護。
- 存在協(xié)調(diào)器單點故障風(fēng)險。
(2)事件編排設(shè)計的優(yōu)缺點:
① 優(yōu)點:
- 避免中央?yún)f(xié)調(diào)器單點故障風(fēng)險。
- 當(dāng)涉及的步驟較少服務(wù)開發(fā)簡單,容易實現(xiàn)。
② 缺點:
- 服務(wù)之間存在循環(huán)依賴的風(fēng)險。
- 當(dāng)涉及的步驟較多,服務(wù)間關(guān)系混亂,難以追蹤調(diào)測。
????????由于 Saga 模型沒有 Prepare 階段,因此事務(wù)間不能保證隔離性。當(dāng)多個 Saga 事務(wù)操作同一資源時,就會產(chǎn)生更新丟失、臟數(shù)據(jù)讀取等問題,這時需要在業(yè)務(wù)層控制并發(fā),例如:在應(yīng)用層面加鎖,或者應(yīng)用層面預(yù)先凍結(jié)資源。
五、本地消息表:
1、什么是本地消息表:
????????本地消息表的核心思路就是將分布式事務(wù)拆分成本地事務(wù)進行處理,在該方案中主要有兩種角色:事務(wù)主動方和事務(wù)被動方。事務(wù)主動發(fā)起方需要額外新建事務(wù)消息表,并在本地事務(wù)中完成業(yè)務(wù)處理和記錄事務(wù)消息,并輪詢事務(wù)消息表的數(shù)據(jù)發(fā)送事務(wù)消息,事務(wù)被動方基于消息中間件消費事務(wù)消息表中的事務(wù)。
????????這樣可以避免以下兩種情況導(dǎo)致的數(shù)據(jù)不一致性:
- 業(yè)務(wù)處理成功、事務(wù)消息發(fā)送失敗
- 業(yè)務(wù)處理失敗、事務(wù)消息發(fā)送成功
2、本地消息表的執(zhí)行流程:
- ① 事務(wù)主動方在同一個本地事務(wù)中處理業(yè)務(wù)和寫消息表操作
- ② 事務(wù)主動方通過消息中間件,通知事務(wù)被動方處理事務(wù)消息。消息中間件可以基于 Kafka、RocketMQ 消息隊列,事務(wù)主動方主動寫消息到消息隊列,事務(wù)消費方消費并處理消息隊列中的消息。
- ③ 事務(wù)被動方通過消息中間件,通知事務(wù)主動方事務(wù)已處理的消息。
- ④ 事務(wù)主動方接收中間件的消息,更新消息表的狀態(tài)為已處理。
一些必要的容錯處理如下:
- 當(dāng)①處理出錯,由于還在事務(wù)主動方的本地事務(wù)中,直接回滾即可
- 當(dāng)②、③處理出錯,由于事務(wù)主動方本地保存了消息,只需要輪詢消息重新通過消息中間件發(fā)送,通知事務(wù)被動方重新讀取消息處理業(yè)務(wù)即可。
- 如果是業(yè)務(wù)上處理失敗,事務(wù)被動方可以發(fā)消息給事務(wù)主動方回滾事務(wù)
- 如果事務(wù)被動方已經(jīng)消費了消息,事務(wù)主動方需要回滾事務(wù)的話,需要發(fā)消息通知事務(wù)主動方進行回滾事務(wù)。
3、本地消息表的優(yōu)缺點:
(1)優(yōu)點:
- 從應(yīng)用設(shè)計開發(fā)的角度實現(xiàn)了消息數(shù)據(jù)的可靠性,消息數(shù)據(jù)的可靠性不依賴于消息中間件,弱化了對 MQ 中間件特性的依賴。
- 方案輕量,容易實現(xiàn)。
(2)缺點:
- 與具體的業(yè)務(wù)場景綁定,耦合性強,不可公用
- 消息數(shù)據(jù)與業(yè)務(wù)數(shù)據(jù)同庫,占用業(yè)務(wù)系統(tǒng)資源
- 業(yè)務(wù)系統(tǒng)在使用關(guān)系型數(shù)據(jù)庫的情況下,消息服務(wù)性能會受到關(guān)系型數(shù)據(jù)庫并發(fā)性能的局限
六、MQ事務(wù)消息:
1、MQ事務(wù)消息的執(zhí)行流程:
????????基于MQ的分布式事務(wù)方案本質(zhì)上是對本地消息表的封裝,整體流程與本地消息表一致,唯一不同的就是將本地消息表存在了MQ內(nèi)部,而不是業(yè)務(wù)數(shù)據(jù)庫中,如下圖:
?????????由于將本地消息表存在了MQ內(nèi)部,那么MQ內(nèi)部的處理尤為重要,下面主要基于 RocketMQ4.3 之后的版本介紹 MQ 的分布式事務(wù)方案
2、RocketMQ事務(wù)消息:
????????在本地消息表方案中,保證事務(wù)主動方發(fā)寫業(yè)務(wù)表數(shù)據(jù)和寫消息表數(shù)據(jù)的一致性是基于數(shù)據(jù)庫事務(wù),而 RocketMQ 的事務(wù)消息相對于普通 MQ提供了 2PC 的提交接口,方案如下:
?(1)正常情況:
在事務(wù)主動方服務(wù)正常,沒有發(fā)生故障的情況下,發(fā)消息流程如下:
- 步驟①:發(fā)送方向 MQ Server(MQ服務(wù)方)發(fā)送 half 消息
- 步驟②:MQ Server 將消息持久化成功之后,向發(fā)送方 ack 確認消息已經(jīng)發(fā)送成功
- 步驟③:發(fā)送方開始執(zhí)行本地事務(wù)邏輯
- 步驟④:發(fā)送方根據(jù)本地事務(wù)執(zhí)行結(jié)果向 MQ Server 提交二次確認(commit 或是 rollback)。
- 最終步驟:MQ Server 如果收到的是 commit 操作,則將半消息標記為可投遞,MQ訂閱方最終將收到該消息;若收到的是 rollback 操作則刪除 half 半消息,訂閱方將不會接受該消息
(2)異常情況:
????????在斷網(wǎng)或者應(yīng)用重啟等異常情況下,圖中的步驟④提交的二次確認超時未到達 MQ Server,此時的處理邏輯如下:
- 步驟⑤:MQ Server 對該消息發(fā)起消息回查
- 步驟⑥:發(fā)送方收到消息回查后,需要檢查對應(yīng)消息的本地事務(wù)執(zhí)行的最終結(jié)果
- 步驟⑦:發(fā)送方根據(jù)檢查得到的本地事務(wù)的最終狀態(tài)再次提交二次確認。
- 最終步驟:MQ Server基于 commit/rollback 對消息進行投遞或者刪除。
3、MQ事務(wù)消息的優(yōu)缺點:
(1)優(yōu)點:相比本地消息表方案,MQ 事務(wù)方案優(yōu)點是:
- 消息數(shù)據(jù)獨立存儲 ,降低業(yè)務(wù)系統(tǒng)與消息系統(tǒng)之間的耦合
- 吞吐量大于使用本地消息表方案
(2)缺點:
- 一次消息發(fā)送需要兩次網(wǎng)絡(luò)請求(half 消息 + commit/rollback 消息) 。
- 業(yè)務(wù)處理服務(wù)需要實現(xiàn)消息狀態(tài)回查接口。
七、最大努力通知:
????????最大努力通知也稱為定期校對,是對MQ事務(wù)方案的進一步優(yōu)化。它在事務(wù)主動方增加了消息校對的接口,如果事務(wù)被動方?jīng)]有接收到主動方發(fā)送的消息,此時可以調(diào)用事務(wù)主動方提供的消息校對的接口主動獲取
?????????在可靠消息事務(wù)中,事務(wù)主動方需要將消息發(fā)送出去,并且讓接收方成功接收消息,這種可靠性發(fā)送是由事務(wù)主動方保證的;但是最大努力通知,事務(wù)主動方僅僅是盡最大努力(重試,輪詢....)將事務(wù)發(fā)送給事務(wù)接收方,所以存在事務(wù)被動方接收不到消息的情況,此時需要事務(wù)被動方主動調(diào)用事務(wù)主動方的消息校對接口查詢業(yè)務(wù)消息并消費,這種通知的可靠性是由事務(wù)被動方保證的。
????????所以最大努力通知適用于業(yè)務(wù)通知類型,例如微信交易的結(jié)果,就是通過最大努力通知方式通知各個商戶,既有回調(diào)通知,也有交易查詢接口。
八、各方案常見使用場景總結(jié):
- 2PC/3PC:依賴于數(shù)據(jù)庫,能夠很好的提供強一致性和強事務(wù)性,但延遲比較高,比較適合傳統(tǒng)的單體應(yīng)用,在同一個方法中存在跨庫操作的情況,不適合高并發(fā)和高性能要求的場景。
- TCC:適用于執(zhí)行時間確定且較短,實時性要求高,對數(shù)據(jù)一致性要求高,比如互聯(lián)網(wǎng)金融企業(yè)最核心的三個服務(wù):交易、支付、賬務(wù)。
- 本地消息表/MQ 事務(wù):適用于事務(wù)中參與方支持操作冪等,對一致性要求不高,業(yè)務(wù)上能容忍數(shù)據(jù)不一致到一個人工檢查周期,事務(wù)涉及的參與方、參與環(huán)節(jié)較少,業(yè)務(wù)上有對賬/校驗系統(tǒng)兜底。
- Saga 事務(wù):由于 Saga 事務(wù)不能保證隔離性,需要在業(yè)務(wù)層控制并發(fā),適合于業(yè)務(wù)場景事務(wù)并發(fā)操作同一資源較少的情況。Saga 由于缺少預(yù)提交動作,導(dǎo)致補償動作的實現(xiàn)比較麻煩,例如業(yè)務(wù)是發(fā)送短信,補償動作則得再發(fā)送一次短信說明撤銷,用戶體驗比較差。所以,Saga 事務(wù)較適用于補償動作容易處理的場景
參考文章:https://blog.csdn.net/qq_34162294/article/details/120984951
總結(jié)
以上是生活随笔為你收集整理的七种常见分布式事务详解(2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通知)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分布式事务Seata原理
- 下一篇: 常见分布式理论(CAP、BASE)和一致