RocketMQ實(shí)現(xiàn)分布式事務(wù)原理

舉個(gè)分布式事務(wù)場(chǎng)景

列子:假設(shè) A 給 B 轉(zhuǎn) 100塊錢(qián),同時(shí)它們不是同一個(gè)服務(wù)上。

目標(biāo):就是 A 減100塊錢(qián),B 加100塊錢(qián)。

實(shí)際情況可能有四種:

1)就是A賬戶(hù)減100 (成功),B賬戶(hù)加100 (成功)
2)就是A賬戶(hù)減100(失?。?,B賬戶(hù)加100 (失?。?br> 3)就是A賬戶(hù)減100(成功),B賬戶(hù)加100 (失?。?br> 4)就是A賬戶(hù)減100 (失?。?,B賬戶(hù)加100 (成功)

這里 第1第2 種情況是能夠保證事務(wù)的一致性的,但是 第3第4 是無(wú)法保證事務(wù)的一致性的。

那我們來(lái)看下RocketMQ是如何來(lái)保證事務(wù)的一致性的

RocketMQ實(shí)現(xiàn)分布式事務(wù)原理

1、基礎(chǔ)概念

  • 最終一致性

RocketMQ是一種最終一致性的分布式事務(wù),就是說(shuō)它保證的是消息最終一致性,而不是像2PC、3PC、TCC那樣強(qiáng)一致分布式事務(wù),至于為什么說(shuō)它是最終一致性事務(wù)下面會(huì)詳細(xì)說(shuō)明。

  • Half Message(半消息)

是指暫不能被Consumer消費(fèi)的消息。Producer 已經(jīng)把消息成功發(fā)送到了 Broker 端,但此消息被標(biāo)記為暫不能投遞狀態(tài),處于該種狀態(tài)下的消息稱(chēng)為半消息。需要 Producer對(duì)消息的二次確認(rèn)后,Consumer才能去消費(fèi)它。

  • 消息回查

由于網(wǎng)絡(luò)閃段,生產(chǎn)者應(yīng)用重啟等原因。導(dǎo)致 Producer 端一直沒(méi)有對(duì) Half Message(半消息) 進(jìn)行 二次確認(rèn)。這是Brock服務(wù)器會(huì)定時(shí)掃描長(zhǎng)期處于半消息的消息,會(huì)主動(dòng)詢(xún)問(wèn)Producer端 該消息的最終狀態(tài)(Commit或者Rollback),該消息即為 消息回查。

2、分布式事務(wù)交互流程

理解這張阿里官方的圖,就能理解RocketMQ分布式事務(wù)的原理了。


image.png

說(shuō)明

1、A服務(wù)先發(fā)送個(gè)Half Message給Brock端,消息中攜帶 B服務(wù) 即將要+100元的信息。
2、當(dāng)A服務(wù)知道Half Message發(fā)送成功后,那么開(kāi)始第3步執(zhí)行本地事務(wù)。
3、執(zhí)行本地事務(wù)(會(huì)有三種情況1、執(zhí)行成功。2、執(zhí)行失敗。3、網(wǎng)絡(luò)等原因?qū)е聸](méi)有響應(yīng))
4.1)、如果本地事務(wù)成功,那么Product像Brock服務(wù)器發(fā)送Commit,這樣B服務(wù)就可以消費(fèi)該message。
4.2)、如果本地事務(wù)失敗,那么Product像Brock服務(wù)器發(fā)送Rollback,那么就會(huì)直接刪除上面這條半消息。
4.3)、如果因?yàn)榫W(wǎng)絡(luò)等原因遲遲沒(méi)有返回失敗還是成功,那么會(huì)執(zhí)行RocketMQ的回調(diào)接口,來(lái)進(jìn)行事務(wù)的回查。

從上面流程可以得知 只有A服務(wù)本地事務(wù)執(zhí)行成功 ,B服務(wù)才能消費(fèi)該message。

然后我們?cè)賮?lái)思考幾個(gè)問(wèn)題?

為什么要先發(fā)送Half Message(半消息)

我覺(jué)得主要有兩點(diǎn):

1)可以先確認(rèn) Brock服務(wù)器是否正常 ,如果半消息都發(fā)送失敗了 那說(shuō)明Brock掛了。
2)可以通過(guò)半消息來(lái)回查事務(wù),如果半消息發(fā)送成功后一直沒(méi)有被二次確認(rèn),那么就會(huì)回查事務(wù)狀態(tài)。

什么情況會(huì)回查

也會(huì)有兩種情況:

1)執(zhí)行本地事務(wù)的時(shí)候,由于突然網(wǎng)絡(luò)等原因一直沒(méi)有返回執(zhí)行事務(wù)的結(jié)果(commit或者rollback)導(dǎo)致最終返回UNKNOW,那么就會(huì)回查。
2) 本地事務(wù)執(zhí)行成功后,返回Commit進(jìn)行消息二次確認(rèn)的時(shí)候的服務(wù)掛了,在重啟服務(wù)那么這個(gè)時(shí)候在brock端
它還是個(gè)Half Message(半消息),這也會(huì)回查。

特別注意: 如果回查,那么一定要先查看當(dāng)前事務(wù)的執(zhí)行情況,再看是否需要重新執(zhí)行本地事務(wù)。
想象下如果出現(xiàn)第二種情況而引起的回查,如果不先查看當(dāng)前事務(wù)的執(zhí)行情況,而是直接執(zhí)行事務(wù),那么就相當(dāng)于成功執(zhí)行了兩個(gè)本地事務(wù)。

為什么說(shuō)MQ是最終一致性事務(wù)

通過(guò)上面這幅圖,我們可以看出,在上面舉例事務(wù)不一致的兩種情況中,永遠(yuǎn)不會(huì)發(fā)生

A賬戶(hù)減100 (失?。?,B賬戶(hù)加100 (成功)

因?yàn)?/strong>:如果A服務(wù)本地事務(wù)都失敗了,那B服務(wù)永遠(yuǎn)不會(huì)執(zhí)行任何操作,因?yàn)橄焊筒粫?huì)傳到B服務(wù)。

那么 A賬戶(hù)減100 (成功),B賬戶(hù)加100 (失?。?會(huì)不會(huì)可能存在的。

答案是會(huì)的

因?yàn)锳服務(wù)只負(fù)責(zé)當(dāng)我消息執(zhí)行成功了,保證消息能夠送達(dá)到B,至于B服務(wù)接到消息后最終執(zhí)行結(jié)果A并不管。

那B服務(wù)失敗怎么辦?

如果B最終執(zhí)行失敗,幾乎可以斷定就是代碼有問(wèn)題所以才引起的異常,因?yàn)橄M(fèi)端RocketMQ有重試機(jī)制,如果不是代碼問(wèn)題一般重試幾次就能成功。

如果是代碼的原因引起多次重試失敗后,也沒(méi)有關(guān)系,將該異常記錄下來(lái),由人工處理,人工兜底處理后,就可以讓事務(wù)達(dá)到最終的一致性。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容