聊一聊分布式事務(wù)


A(Atomicity):指單個(gè)事務(wù)中的操作要不都執(zhí)行,要不都不執(zhí)行
C(Consistency):指事務(wù)前后數(shù)據(jù)的完整性必須保持一致
I(Isolation):指多個(gè)事務(wù)對數(shù)據(jù)可見性的規(guī)則
D(Durability):指事務(wù)提交后,就會被永久存儲下來
準(zhǔn)備階段,協(xié)調(diào)者分別給每個(gè)參與者發(fā)送Prepare消息,每個(gè)參與者收到消息后,進(jìn)行“預(yù)提交”操作(不是實(shí)際的提交操作),把操作的結(jié)果(成功或失敗)返回給協(xié)調(diào)者。
提交階段,協(xié)調(diào)者根據(jù)準(zhǔn)備階段收到的參與者的返回結(jié)果進(jìn)行判斷,如果所有的參與者都返回成功,那么分別給每個(gè)參與者發(fā)送Commit消息,否則發(fā)送Rollback消息。

同步阻塞,2PC的兩個(gè)階段中,協(xié)調(diào)者和參與者的通信都是同步的,這會導(dǎo)致整個(gè)事務(wù)的長時(shí)間阻塞
Coordinator的單點(diǎn)問題
數(shù)據(jù)不一致,在Commit階段,可能存在只有部分參與者收到Commit消息(或處理成功)的情況

事務(wù)發(fā)起方把要處理的業(yè)務(wù)事務(wù)和寫消息表這兩個(gè)操作放在同一個(gè)本地事務(wù)里
事務(wù)發(fā)起方有一個(gè)定時(shí)任務(wù)輪詢消息表,把沒處理的消息發(fā)送到消息中間件
事務(wù)被動方從消息中間件獲取消息后,返回成功
事務(wù)發(fā)起方更新消息狀態(tài)為已成功

把業(yè)務(wù)處理和寫消息表放在同一個(gè)事務(wù)是為了失敗/異常后可以同時(shí)回滾
為什么不直接發(fā)消息,而是先寫消息表?試想,如果發(fā)送消息超時(shí)了,即不確定消息中間件收到消息沒,那么你是重試還是拋異?;貪L事務(wù)呢?回滾是不行的,因?yàn)榭赡芟⒅虚g件已經(jīng)收到消息,接收方收到消息后做處理,導(dǎo)致雙方數(shù)據(jù)不一致了;重試也是不行的,因?yàn)橛锌赡軙恢敝卦囀?,?dǎo)致事務(wù)阻塞。
基于上述分析,消息的接收方是需要做冪等操作的
消息數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù)耦合,消息表需要根據(jù)具體的業(yè)務(wù)場景制定,不能公用。就算可以公用消息表,對于分庫的業(yè)務(wù)來說每個(gè)庫都是需要消息表的。
只適用于最終一致的業(yè)務(wù)場景。例如在 A -> B場景下,在不考慮網(wǎng)絡(luò)異常、宕機(jī)等非業(yè)務(wù)異常的情況下,A成功的話,B肯定也會成功的。
發(fā)起方發(fā)送半事務(wù)消息會給RocketMQ ,此時(shí)消息的狀態(tài)prepare,接受方還不能拉取到此消息
發(fā)起方進(jìn)行本地事務(wù)操作
發(fā)起方給RocketMQ確認(rèn)提交消息,此時(shí)接受方可以消費(fèi)到此消息了

Try階段,對業(yè)務(wù)資源進(jìn)行檢測和預(yù)留
Confirm階段,對Try階段預(yù)留的資源進(jìn)行確認(rèn)提交,Try階段執(zhí)行成功是Confirm階段執(zhí)行成功的前提
Cancel階段,對Try階段預(yù)留的資源進(jìn)行撤銷或釋放

如果Try成功了,那么Confirm階段異常了就一直重試,直到成功
Try、Confirm、Cancel三個(gè)階段都有相應(yīng)的資源及事務(wù)日志,應(yīng)用根據(jù)日志(異步)來做重試或補(bǔ)償
TCC的實(shí)現(xiàn)依賴底層數(shù)據(jù)庫,異常后直接利用數(shù)據(jù)庫的事務(wù)機(jī)制回滾
允許空回滾,在Try沒有真正執(zhí)行的情況下,觸發(fā)了Cancel操作,這時(shí)要允許Cancel成功
防懸掛控制,Cancel操作比Try操作先執(zhí)行(網(wǎng)絡(luò)延遲原因),后面的Try操作不能執(zhí)行成功
冪等控制
對于Confirm和Cancel階段失敗后要完全靠業(yè)務(wù)應(yīng)用自己去處理
每個(gè)業(yè)務(wù)都需要實(shí)現(xiàn)Try、Confirm、Cancel三個(gè)接口,代碼量比較多
如果是基于現(xiàn)有的業(yè)務(wù)想使用TCC會比較困難。一是對于原來的接口要拆分為三個(gè)接口,入侵性比較大;二是因?yàn)橐觥邦A(yù)留”資源的操作,有可能需要對原來的業(yè)務(wù)模型進(jìn)行改造。

TCC適用于執(zhí)行時(shí)間確定且較短、對一致性要求比較高、數(shù)據(jù)隔離強(qiáng)的業(yè)務(wù)
Saga適用于業(yè)務(wù)流程長、業(yè)務(wù)流程多的業(yè)務(wù),在銀行業(yè)金融機(jī)構(gòu)使用廣泛
TCC對現(xiàn)有業(yè)務(wù)改造較大,Saga則相對少點(diǎn)


總得看來,分布式事務(wù)的解決方案都很難做到有高一致性的同時(shí),也有高性能,同時(shí)在實(shí)現(xiàn)上也有一定的難度。在業(yè)務(wù)允許的情況下,我們通常處理分布式事務(wù)的一般原則應(yīng)是:業(yè)務(wù)規(guī)避 > 最終一致 > 強(qiáng)一致。
文章轉(zhuǎn)自:分布式實(shí)驗(yàn)室(版權(quán)歸原作者所有,侵刪)
![]()
