RocketMQ實戰(zhàn)(三):分布式事務(wù)

《RocketMQ實戰(zhàn)(一)》扫俺,《RocketMQ實戰(zhàn)(二)》,本篇博客主要討論的話題是:順序消費火脉、RMQ在分布式事務(wù)中的應(yīng)用等牵舵。

關(guān)于多Master多Slave的說明

由于在之前的博客中已經(jīng)搭建了雙Master柒啤,其實多Master多Slave大同小異,因此這里并不會一步步的演示搭建多Master多Slave畸颅,而是從思路上担巩,分析下重點應(yīng)該注意的配置項。

多Master多Slave

第一没炒,這四臺機器涛癌,對外是一個統(tǒng)一的整體,是一個rocketmq cluster送火,因此需要brokerClusterName保持統(tǒng)一

第二拳话,123機器是121的從,124機器是122的從种吸,如何在配置中體現(xiàn)弃衍? 主和從的brokerName需要保持一致,另外brokerId標(biāo)示了誰是主坚俗,誰是從(brokerId=0的就是主镜盯,大于0的就是從)

第三,注意namesrvAddr的地址是4臺NameServer

第四猖败,配置項中brokerRole需要指明 ASYNC_MASTER(異步復(fù)制Master) or SYNC_MASTER(同步雙寫Master) or SLAVE(從)

第五速缆,和以前的多Master啟動方式一致,先啟動4臺Namesrv恩闻,然后用指定配置文件的方式啟動Master/Slave即可

第六艺糜,多Master多Slave的好處在于,即便集群中某個broker掛了幢尚,也可以繼續(xù)消費破停,保證了實時性的高可用,但是并不是說某個master掛了侠草,slave就可以升級master辱挥,開源版本的rocketmq是不可以的。也就是說边涕,在這種情況下晤碘,slave只能提供讀的功能,將失去消息負(fù)載的能力功蜓。


Queue in Topic

對于RocketMQ而言园爷,Topic只是一個邏輯上的概念,真正的消息存儲其實是在Topic中的Queue中式撼。想一想童社,為什么RocketMQ要這要設(shè)計呢?其實是為了消息的順序消費著隆,后文中將為大家介紹扰楼。


queue in topic


默認(rèn)一個Topic中4個隊列


配置文件中指定


初步認(rèn)識RocketMQ的核心模塊


rocketmq模塊

rocketmq-broker:接受生產(chǎn)者發(fā)來的消息并存儲(通過調(diào)用rocketmq-store)呀癣,消費者從這里取得消息。

rocketmq-client:提供發(fā)送弦赖、接受消息的客戶端API项栏。

rocketmq-namesrv:NameServer,類似于Zookeeper蹬竖,這里保存著消息的TopicName沼沈,隊列等運行時的元信息。(有點NameNode的味道)

rocketmq-common:通用的一些類币厕,方法列另,數(shù)據(jù)結(jié)構(gòu)等

rocketmq-remoting:基于Netty4的client/server + fastjson序列化 + 自定義二進(jìn)制協(xié)議

rocketmq-store:消息、索引存儲等

rocketmq-filtersrv:消息過濾器Server旦装,需要注意的是页衙,要實現(xiàn)這種過濾,需要上傳代碼到MQ同辣!【一般而言拷姿,我們利用Tag足以滿足大部分的過濾需求,如果更靈活更復(fù)雜的過濾需求旱函,可以考慮filtersrv組件】

rocketmq-tools:命令行工具


Order Message

RocketMQ提供了3種模式的Producer:

NormalProducer(普通)、OrderProducer(順序)描滔、TransactionProducer(事務(wù))

在前面的博客當(dāng)中棒妨,涉及的都是NormalProducer,調(diào)用傳統(tǒng)的send方法含长,消息是無序的券腔。接下來,我們來看看順序消費拘泞。模擬這樣一個場景纷纫,如果一個用戶完成一個訂單需要3條消息,比如訂單的創(chuàng)建陪腌、訂單的支付辱魁、訂單的發(fā)貨,很顯然诗鸭,同一個用戶的訂單消息必須要順序消費染簇,但是不同用戶之間的訂單可以并行消費。

生產(chǎn)者端代碼示例:

順序消息模式

注意强岸,一個Message除了Topic/Tag外锻弓,還有Key的概念。

上圖的send方法不同于以往蝌箍,有一個MessageQueueSelector青灼,將用于指定特定的消息發(fā)往特定的隊列當(dāng)中暴心!


順序消費

注意在以前普通消費消息時設(shè)置的回調(diào)是MessageListenerConcurrently,而順序消費的回調(diào)設(shè)置是MessageListenerOrderly杂拨。

當(dāng)我們啟動2個Consumer進(jìn)行消費時专普,可以觀察到:

多個消費者消費的結(jié)果

可以觀察得到,雖然從全局上來看扳躬,消息的消費不是有序的脆诉,但是每一個訂單下的3條消息是順序消費的!

其實贷币,如果需要保證消息的順序消費击胜,那么很簡單,首先需要做到一組需要有序消費的消息發(fā)往同一個broker的同一個隊列上役纹!其次消費者端采用有序Listener即可偶摔。

這里,RocketMQ底層是如何做到消息順序消費的促脉,看一看源碼你就能大概了解到辰斋,至少來說,在多線程消費場景下瘸味,一個線程只去消費一個隊列上的消息宫仗,那么自然就保證了消息消費的順序性,同時也保證了多個線程之間的并發(fā)性旁仿。也就是說其實broker并不能完全保證消息的順序消費藕夫,它僅僅能保證的消息的順序發(fā)送而已!

關(guān)于多線程消費這塊枯冈,RocketMQ早就替我們想好了毅贮,這樣設(shè)置即可:

消費多線程設(shè)置

想一想,在ActiveMQ中尘奏,我們?nèi)绻雽崿F(xiàn)并發(fā)消費的話滩褥,恐怕還得搞個線程池提交任務(wù)吧,RocketMQ讓我們的工作變得簡單炫加!


Transaction Message

在說事務(wù)消息之前瑰煎,我們先來說說分布式事務(wù)的那些事!

什么是分布式事務(wù)琢感,我的理解是一半事務(wù)丢间。怎么說,比如有2個異構(gòu)系統(tǒng)驹针,A異構(gòu)系統(tǒng)要做T1烘挫,B異構(gòu)系統(tǒng)要做T2,要么都成功,要么都失敗饮六。

要知道異構(gòu)系統(tǒng)其垄,很顯然,不在一個數(shù)據(jù)庫實例上卤橄,它們往往分布在不同物理節(jié)點上绿满,本地事務(wù)已經(jīng)失效。

2階段提交

2階段提交協(xié)議窟扑,Two-Phase Commit喇颁,是處理分布式事務(wù)的一種常見手段。2PC嚎货,存在2個重要角色:事務(wù)協(xié)調(diào)器(TC)橘霎,事務(wù)執(zhí)行者。

2PC殖属,可以看到節(jié)點之間的通信次數(shù)太多了姐叁,時間很長!時間變長了洗显,從而導(dǎo)致外潜,事務(wù)鎖定的資源時間也變長了,造成資源等待時間變長挠唆!在高并發(fā)場景下处窥,存在嚴(yán)重的性能問題!

下面玄组,我們來看看MQ在高并發(fā)場景下碧库,是如何解決分布式事務(wù)的。

考慮生活中的場景:

我們?nèi)ケ本c豐包子鋪吃炒肝巧勤,先去營業(yè)員那里付款(Action1),拿到小票(Ticket)弄匕,然后去取餐窗口排隊拿炒肝(Action2)颅悉。思考2個問題:第一,為什么不在付款的同時迁匠,給顧客炒肝剩瓶?如果這樣的話,會增加處理時間城丧,使得后面的顧客等待時間變長延曙,相當(dāng)于降低了接待顧客的能力(降低了系統(tǒng)的QPS)。第二亡哄,付了款枝缔,拿到的是Ticket,顧客為什么會接受?從心理上說愿卸,顧客相信Ticket會兌現(xiàn)炒肝灵临。事實上也是如此,就算在最后炒肝沒了趴荸,或者斷電斷水(系統(tǒng)出現(xiàn)異常)儒溉,顧客依然可以通過Ticket進(jìn)行退款操作,這樣都不會有什么損失7⒍邸(雖然這么說顿涣,但是實際上包子鋪最大化了它的利益,如果炒肝真的沒了酝豪,浪費了顧客的時間涛碑,不過顧客頂多發(fā)發(fā)牢騷,最后接受)

生活已經(jīng)告訴我們處理分布式事務(wù)寓调,保證數(shù)據(jù)最終一致性的思路锌唾!這個Ticket(憑證)其實就是消息!

業(yè)務(wù)和消息生成耦合在一起

業(yè)務(wù)操作和消息的生成耦合在一起夺英,保證了只要A銀行的賬戶發(fā)生扣款晌涕,那么一定會生成一條轉(zhuǎn)賬消息。只要A銀行系統(tǒng)的事務(wù)成功提交痛悯,我們可以通過實時消息服務(wù)余黎,將轉(zhuǎn)賬消息通知B銀行系統(tǒng),如果B銀行系統(tǒng)回復(fù)成功载萌,那么A銀行系統(tǒng)可以在table中設(shè)置這條轉(zhuǎn)賬消息的狀態(tài)惧财。

這樣耦合的方式,從架構(gòu)上來看扭仁,就有點不太優(yōu)雅垮衷,而且存在一些問題。比如說乖坠,消息的存儲實質(zhì)上是在A銀行系統(tǒng)中的搀突,如果A銀行系統(tǒng)出了問題,將導(dǎo)致無法轉(zhuǎn)賬熊泵。如果解耦仰迁,將消息獨立出來呢?

業(yè)務(wù)和消息解耦

如上圖所示顽分,消息數(shù)據(jù)獨立存儲徐许,業(yè)務(wù)和消息解耦,實質(zhì)上消息的發(fā)送有2次卒蘸,一條是轉(zhuǎn)賬消息雌隅,另一條是確認(rèn)消息。

到這里,我們先來看看基于RocketMQ的代碼:

生產(chǎn)者示例代碼

生產(chǎn)者這里用到是:TransactionMQProducer澄步。

這里涉及到2個角色:本地事務(wù)執(zhí)行器(代碼中的TransactionExecuterImpl)冰蘑、服務(wù)器回查客戶端Listener(代碼中的TransactionCheckListener)。

如果事務(wù)消息發(fā)送到MQ上后村缸,會回調(diào) ?本地事務(wù)執(zhí)行器祠肥;但是此時事務(wù)消息是prepare狀態(tài),對消費者還不可見梯皿,需要 ?本地事務(wù)執(zhí)行器 ?返回RMQ一個確認(rèn)消息仇箱。


本地事務(wù)執(zhí)行器

事務(wù)消息是否對消費者可見,完全由事務(wù)返回給RMQ的狀態(tài)碼決定(狀態(tài)碼的本質(zhì)也是一條消息)东羹。


回查Listener


運行結(jié)果

生產(chǎn)者發(fā)送了2條消息給RMQ剂桥,有一條本地事務(wù)執(zhí)行成功,有一條本地事務(wù)執(zhí)行失敗属提。

2條業(yè)務(wù)消息 + 2條確認(rèn)消息 ?因此是4條权逗;

注意到消費者只消費了一條數(shù)據(jù),就是只有告訴RMQ本地事務(wù)執(zhí)行成功的那條消息才會被消費冤议!因此是1條斟薇!

但是,注意到本地事務(wù)執(zhí)行失敗的消息恕酸,RMQ并沒有check listener堪滨?這是為什么呢?因為RMQ在3.0.8的時候還是支持check listener回查機制的蕊温,但是到了3.2.6的時候?qū)⑹聞?wù)回查機制“閹割”了袱箱!

那么3.0.8的時候,RMQ是怎么做事務(wù)回查的呢义矛?看一看源碼发笔,你會知道,其實事務(wù)消息開始是prepare狀態(tài)凉翻,然后RMQ會將其持久化到MySQL當(dāng)中筐咧,然后如果收到確認(rèn)消息,就刪除掉這條prepare消息噪矛,如果遲遲收不到確認(rèn)消息,那么RMQ會定時的掃描prepare消息铺罢,發(fā)送給produce group進(jìn)行回查確認(rèn)艇挨!

到這里,問題來了韭赘,要知道3.2.6版本缩滨,沒有回查機制了,會存在問題么?

當(dāng)然會存在問題脉漏!假設(shè)苞冯,我們發(fā)送一條轉(zhuǎn)賬事務(wù)消息給RMQ,成功后回調(diào)本地事務(wù)侧巨,DB減操作成功舅锄,剛準(zhǔn)備給RMQ一個確認(rèn)消息,此時突然斷電司忱,或者網(wǎng)絡(luò)抖動皇忿,使得這條確認(rèn)消息沒有發(fā)送出去。此時RMQ中的那條轉(zhuǎn)賬事務(wù)消息坦仍,始終處于prepare狀態(tài)鳍烁,消費者讀取不到,但是卻已經(jīng)完成一方的賬戶資金變動7痹a;摹!

既然梳玫,RMQ3.2.6版本不為我們進(jìn)行回查爹梁,那么只能由我們自己完成了。具體怎么做呢汽纠,咱們下期再來分析~?

see u , good night~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卫键,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子虱朵,更是在濱河造成了極大的恐慌莉炉,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碴犬,死亡現(xiàn)場離奇詭異絮宁,居然都是意外死亡,警方通過查閱死者的電腦和手機服协,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門绍昂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人偿荷,你說我怎么就攤上這事窘游。” “怎么了跳纳?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵忍饰,是天一觀的道長。 經(jīng)常有香客問我寺庄,道長艾蓝,這世上最難降的妖魔是什么力崇? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮赢织,結(jié)果婚禮上亮靴,老公的妹妹穿的比我還像新娘。我一直安慰自己于置,他們只是感情好茧吊,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俱两,像睡著了一般饱狂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宪彩,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天休讳,我揣著相機與錄音,去河邊找鬼尿孔。 笑死俊柔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的活合。 我是一名探鬼主播雏婶,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼白指!你這毒婦竟也來了留晚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤告嘲,失蹤者是張志新(化名)和其女友劉穎错维,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體橄唬,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡赋焕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了仰楚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隆判。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖僧界,靈堂內(nèi)的尸體忽然破棺而出侨嘀,到底是詐尸還是另有隱情,我是刑警寧澤捂襟,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布飒炎,位于F島的核電站,受9級特大地震影響笆豁,放射性物質(zhì)發(fā)生泄漏郎汪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一闯狱、第九天 我趴在偏房一處隱蔽的房頂上張望煞赢。 院中可真熱鬧,春花似錦哄孤、人聲如沸照筑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凝危。三九已至,卻和暖如春晨逝,著一層夾襖步出監(jiān)牢的瞬間蛾默,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工捉貌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留支鸡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓趁窃,卻偏偏與公主長得像牧挣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子醒陆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容