日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

RocketMQ的分布式事务解决方案

發(fā)布時(shí)間:2024/1/23 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RocketMQ的分布式事务解决方案 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

在系統(tǒng)變的復(fù)雜后,分布式、微服務(wù)等架構(gòu)技術(shù),就要考慮到應(yīng)用在系統(tǒng)中了。尤其數(shù)據(jù)量大了后,就需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行拆分

如:注冊(cè)的用戶數(shù)據(jù),量大了后,就需要考慮分庫(kù)分表

一旦數(shù)據(jù)庫(kù)進(jìn)行了分拆,那就出現(xiàn)很多頭疼的問(wèn)題,其中之一就是事務(wù)問(wèn)題。那我們就來(lái)看看問(wèn)題是怎么出現(xiàn)的?

場(chǎng)景

?

?

先來(lái)上個(gè)圖

進(jìn)行數(shù)據(jù)拆分后,就類似上面的架構(gòu)

上圖中我們就拿用戶的數(shù)據(jù)進(jìn)行舉例,用戶量一旦幾千萬(wàn)時(shí),就需要進(jìn)行分庫(kù)分表;上圖就分了3個(gè)庫(kù),每個(gè)庫(kù)都保證了高可用。

這樣的架構(gòu)設(shè)計(jì),會(huì)遇到事務(wù)問(wèn)題,我們來(lái)看看具體的業(yè)務(wù)場(chǎng)景:用戶A轉(zhuǎn)賬100元給用戶B,這個(gè)業(yè)務(wù)比較簡(jiǎn)單,我們來(lái)分析一下里面具體的步驟

1、用戶A的賬戶先扣除100元 2、再把用戶B的賬戶加100元

?

?

邏輯很簡(jiǎn)單,上偽代碼

代碼也是比較清晰的,感覺(jué)沒(méi)有什么問(wèn)題,那我們來(lái)分析一下問(wèn)題在哪?

問(wèn)題

我們看到在轉(zhuǎn)賬業(yè)務(wù)中,有兩步,一個(gè)是操作用戶A扣錢,一個(gè)是操作用戶B加錢

如果在同一個(gè)數(shù)據(jù)庫(kù)中進(jìn)行,可以保證這兩步操作,要么同時(shí)成功,要么同時(shí)不成功。這樣就保證了轉(zhuǎn)賬的數(shù)據(jù)一致性。

但是如果用戶A的數(shù)據(jù)在集群A中,用戶B在集群B中呢?因?yàn)?strong>他們不在同一個(gè)事務(wù)中;如用戶A扣款成功,但用戶B加錢失敗了;那就坑了,數(shù)據(jù)不完整了。

類似這種問(wèn)題在微服務(wù)架構(gòu)會(huì)更多,因?yàn)楦鱾€(gè)服務(wù)都是獨(dú)立的模塊,都是遠(yuǎn)程調(diào)用,都沒(méi)法在同一個(gè)事務(wù)中,都會(huì)遇到事務(wù)問(wèn)題。

那怎么解決?網(wǎng)上有一些方案,如:兩階段提交,TCC等,還有常用就是最終一致性方案。今天就給大家介紹一下如何利用消息中間件去解決。那我們就把方案調(diào)整一下,加入消息中間件,看看如何優(yōu)化。

消息中間件方案

上圖就是利用消息中間件的方式,把扣款業(yè)務(wù)和加錢業(yè)務(wù)異步化,扣款成功后,發(fā)送“扣款成功消息”到消息中間件;加錢業(yè)務(wù)訂閱“扣款成功消息”,再對(duì)用戶B加錢

系統(tǒng)怎么知道給用戶B加錢呢?是消息體里面包含了源賬戶和目標(biāo)賬戶ID,以及錢數(shù)

這個(gè)時(shí)候也許小伙伴們會(huì)問(wèn),應(yīng)該也有問(wèn)題吧:場(chǎng)景一:先扣款后發(fā)消息

先扣款再發(fā)送消息,萬(wàn)一發(fā)送消息失敗了,那用戶B就沒(méi)法加錢

那把順序調(diào)整一下場(chǎng)景二:先發(fā)消息,后扣款

扣款成功消息發(fā)送成功,但用戶A扣款失敗,可加錢業(yè)務(wù)訂閱到了消息,用戶B加了錢

大家應(yīng)該發(fā)現(xiàn)了問(wèn)題所在,也就是沒(méi)法保證扣款和發(fā)送消息,同時(shí)成功,或同時(shí)失敗;導(dǎo)致數(shù)據(jù)不一致。

RocketMQ事務(wù)方案

因?yàn)樯厦娴膯?wèn)題,RocketMq消息中間件把消息分為兩個(gè)階段Prepared階段確認(rèn)階段Prepared階段(預(yù)備階段)

該階段主要發(fā)一個(gè)消息到rocketmq,但該消息只儲(chǔ)存在commitlog中但consumeQueue中不可見(jiàn),也就是消費(fèi)端(訂閱端)無(wú)法看到此消息

commit/rollback階段(確認(rèn)階段)

該階段主要是把prepared消息保存到consumeQueue中,即讓消費(fèi)端可以看到此消息,也就是可以消費(fèi)此消息

?

?

我們用圖來(lái)說(shuō)明下:

整個(gè)流程

1、在扣款之前,先發(fā)送預(yù)備消息
2、發(fā)送預(yù)備消息成功后,執(zhí)行本地扣款事務(wù)
3、扣款成功后,再發(fā)送確認(rèn)消息
4、消息端(加錢業(yè)務(wù))可以看到確認(rèn)消息,消費(fèi)此消息,進(jìn)行加錢

確認(rèn)消息說(shuō)明

注意:上面的確認(rèn)消息可以為commit消息,可以被訂閱者消費(fèi);也可以是Rollback消息,即執(zhí)行本地扣款事務(wù)失敗后,提交rollback消息,即刪除那個(gè)預(yù)備消息,訂閱者無(wú)法消費(fèi)

我們來(lái)分析一下異常場(chǎng)景

異常1:如果發(fā)送預(yù)備消息失敗,下面的流程不會(huì)走下去;這個(gè)是正常的
異常2:
如果發(fā)送預(yù)備消息成功,但執(zhí)行本地事務(wù)失敗;這個(gè)也沒(méi)有問(wèn)題,因?yàn)榇祟A(yù)備消息不會(huì)被消費(fèi)端訂閱到,消費(fèi)端不會(huì)執(zhí)行業(yè)務(wù)。
異常3:
如果發(fā)送預(yù)備消息成功,執(zhí)行本地事務(wù)成功,但發(fā)送確認(rèn)消息失敗;這個(gè)就有問(wèn)題了,因?yàn)橛脩鬉扣款成功了,但加錢業(yè)務(wù)沒(méi)有訂閱到確認(rèn)消息,無(wú)法加錢。這里出現(xiàn)了數(shù)據(jù)不一致。

那RocketMq是怎么解決的呢?

RocketMQ回查

image

RocketMq如何解決上面的問(wèn)題,核心思路就是【狀態(tài)回查】,也就是RocketMq會(huì)定時(shí)遍歷commitlog中的預(yù)備消息。

因?yàn)轭A(yù)備消息最終肯定會(huì)變?yōu)閏ommit消息或Rollback消息,所以遍歷預(yù)備消息去回查本地業(yè)務(wù)的執(zhí)行狀態(tài),如果發(fā)現(xiàn)本地業(yè)務(wù)沒(méi)有執(zhí)行成功就rollBack,如果執(zhí)行成功就發(fā)送commit消息。

上面的異常3,發(fā)送預(yù)備消息成功,本地扣款事務(wù)成功,但發(fā)送確認(rèn)消息失敗;因?yàn)?strong>RocketMq會(huì)進(jìn)行回查預(yù)備消息,在回查后發(fā)現(xiàn)業(yè)務(wù)已經(jīng)扣款成功了,就補(bǔ)發(fā)“發(fā)送commit確認(rèn)消息”;這樣加錢業(yè)務(wù)就可以訂閱此消息了。

這個(gè)思路其實(shí)把異常2也解決了,因?yàn)楸镜厥聞?wù)沒(méi)有執(zhí)行成功,RocketMQ回查業(yè)務(wù),發(fā)現(xiàn)沒(méi)有執(zhí)行成功,就會(huì)發(fā)送RollBack確認(rèn)消息,把消息進(jìn)行刪除

回查判斷業(yè)務(wù)是否成功

小伙伴們?cè)诨夭闃I(yè)務(wù)中,如何判斷本地事務(wù)是否執(zhí)行成功

如果本地事務(wù)執(zhí)行了很多張表,那是不是我們要把那些表都要進(jìn)行判斷是否執(zhí)行成功呢?這樣是不是太麻煩了,而且和業(yè)務(wù)很耦合。

有沒(méi)有更好的方式呢?就是設(shè)計(jì)一張Transaction表,將業(yè)務(wù)表和Transaction綁定在同一個(gè)本地事務(wù)中,如果扣款本地事務(wù)成功時(shí),Transaction中應(yīng)當(dāng)已經(jīng)記錄該TransactionId的狀態(tài)為「已完成」。當(dāng)RocketMq回查時(shí),只需要檢查對(duì)應(yīng)的TransactionId的狀態(tài)是否是「已完成」就好,而不用關(guān)心具體的業(yè)務(wù)數(shù)據(jù)。



作者:消失er
鏈接:https://www.jianshu.com/p/286cac4625b6
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

總結(jié)

以上是生活随笔為你收集整理的RocketMQ的分布式事务解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。