高并發(fā)場(chǎng)景下,如何保證生產(chǎn)者投遞到消息中間件的消息不丟失有序?

如果投遞出去的消息在網(wǎng)絡(luò)傳輸過程中丟失抹腿,或者在RabbitMQ的內(nèi)存中還沒寫入磁盤的時(shí)候宕機(jī),都會(huì)導(dǎo)致生產(chǎn)端投遞到MQ的數(shù)據(jù)丟失旭寿。

而且丟失之后警绩,生產(chǎn)端自己還感知不到,同時(shí)還沒辦法來(lái)補(bǔ)救盅称。

下面的圖就展示了這個(gè)問題肩祥。

所以本文呢,我們就來(lái)逐步分析一下缩膝。

2

保證投遞消息不丟失的confirm機(jī)制

其實(shí)要解決這個(gè)問題混狠,相信大家看過之前的消費(fèi)端ack機(jī)制之后,也都猜到了疾层。

很簡(jiǎn)單将饺,就是生產(chǎn)端(比如上圖的訂單服務(wù))首先需要開啟一個(gè)confirm模式,接著投遞到MQ的消息痛黎,如果MQ一旦將消息持久化到磁盤之后予弧,必須也要回傳一個(gè)confirm消息給生產(chǎn)端。

這樣的話湖饱,如果生產(chǎn)端的服務(wù)接收到了這個(gè)confirm消息掖蛤,就知道是已經(jīng)持久化到磁盤了。

否則如果沒有接收到confirm消息井厌,那么就說明這條消息半路可能丟失了蚓庭,此時(shí)你就可以重新投遞消息到MQ去,確保消息不要丟失旗笔。

而且一旦你開啟了confirm模式之后彪置,每次消息投遞也同樣是有一個(gè)delivery tag的,也是起到唯一標(biāo)識(shí)一次消息投遞的作用蝇恶。

這樣拳魁,MQ回傳ack給生產(chǎn)端的時(shí)候,會(huì)帶上這個(gè)delivery tag撮弧。你就知道具體對(duì)應(yīng)著哪一次消息投遞了潘懊,可以刪除這條消息姚糊。

此外,如果RabbitMQ接收到一條消息之后授舟,結(jié)果內(nèi)部出錯(cuò)發(fā)現(xiàn)無(wú)法處理這條消息救恨,那么他會(huì)回傳一個(gè)nack消息給生產(chǎn)端。此時(shí)你就會(huì)感知到這條消息可能處理有問題释树,你可以選擇重新再次投遞這條消息到MQ去肠槽。

或者另一種情況,如果某條消息很長(zhǎng)時(shí)間都沒給你回傳ack/nack奢啥,那可能是極端意外情況發(fā)生了秸仙,數(shù)據(jù)也丟了,你也可以自己重新投遞消息到MQ去桩盲。

通過這套confirm機(jī)制寂纪,就可以實(shí)現(xiàn)生產(chǎn)端投遞消息不會(huì)丟失的效果。大家來(lái)看看下面的圖赌结,一起來(lái)感受一下捞蛋。

3

confirm機(jī)制的代碼實(shí)現(xiàn)

下面,我們?cè)賮?lái)看看confirm機(jī)制的代碼實(shí)現(xiàn):

4

confirm機(jī)制投遞消息的高延遲性

這里有一個(gè)很關(guān)鍵的點(diǎn)柬姚,就是一旦啟用了confirm機(jī)制投遞消息到MQ之后拟杉,MQ是不保證什么時(shí)候會(huì)給你一個(gè)ack或者nack的。

因?yàn)镽abbitMQ自己內(nèi)部將消息持久化到磁盤伤靠,本身就是通過異步批量的方式來(lái)進(jìn)行的捣域。

正常情況下,你投遞到RabbitMQ的消息都會(huì)先駐留在內(nèi)存里宴合,然后過了幾百毫秒的延遲時(shí)間之后焕梅,再一次性批量把多條消息持久化到磁盤里去。

這樣做卦洽,是為了兼顧高并發(fā)寫入的吞吐量和性能的贞言,因?yàn)橐悄銇?lái)一條消息就寫一次磁盤,那么性能會(huì)很差阀蒂,每次寫磁盤都是一次fsync強(qiáng)制刷入磁盤的操作该窗,是很耗時(shí)的。

所以正是因?yàn)檫@個(gè)原因蚤霞,你打開了confirm模式之后酗失,很可能你投遞出去一條消息,要間隔幾百毫秒之后昧绣,MQ才會(huì)把消息寫入磁盤规肴,接著你才會(huì)收到MQ回傳過來(lái)的ack消息,這個(gè)就是所謂confirm機(jī)制投遞消息的高延遲性

大家看看下面的圖拖刃,一起來(lái)感受一下删壮。

5

高并發(fā)下如何投遞消息才能不丟失

大家可以考慮一下,在生產(chǎn)端高并發(fā)寫入MQ的場(chǎng)景下兑牡,你會(huì)面臨兩個(gè)問題:

1央碟、你每次寫一條消息到MQ,為了等待這條消息的ack均函,必須把消息保存到一個(gè)存儲(chǔ)里亿虽。

并且這個(gè)存儲(chǔ)不建議是內(nèi)存,因?yàn)楦卟l(fā)下消息是很多的苞也,每秒可能都幾千甚至上萬(wàn)的消息投遞出去经柴,消息的ack要等幾百毫秒的話,放內(nèi)存可能有內(nèi)存溢出的風(fēng)險(xiǎn)墩朦。

2、絕對(duì)不能以同步寫消息 + 等待ack的方式來(lái)投遞翻擒,那樣會(huì)導(dǎo)致每次投遞一個(gè)消息都同步阻塞等待幾百毫秒氓涣,會(huì)導(dǎo)致投遞性能和吞吐量大幅度下降。

針對(duì)這兩個(gè)問題陋气,相對(duì)應(yīng)的方案其實(shí)也呼之欲出了劳吠。

首先,用來(lái)臨時(shí)存放未ack消息的存儲(chǔ)需要承載高并發(fā)寫入巩趁,而且我們不需要什么復(fù)雜的運(yùn)算操作痒玩,這種存儲(chǔ)首選絕對(duì)不是MySQL之類的數(shù)據(jù)庫(kù),而建議采用kv存儲(chǔ)议慰。kv存儲(chǔ)承載高并發(fā)能力極強(qiáng)蠢古,而且kv操作性能很高。

其次别凹,投遞消息之后等待ack的過程必須是異步的草讶,也就是類似上面那樣的代碼,已經(jīng)給出了一個(gè)初步的異步回調(diào)的方式炉菲。

消息投遞出去之后堕战,這個(gè)投遞的線程其實(shí)就可以返回了,至于每個(gè)消息的異步回調(diào)拍霜,是通過在channel注冊(cè)一個(gè)confirm監(jiān)聽器實(shí)現(xiàn)的嘱丢。

收到一個(gè)消息ack之后,就從kv存儲(chǔ)中刪除這條臨時(shí)消息祠饺;收到一個(gè)消息nack之后越驻,就從kv存儲(chǔ)提取這條消息然后重新投遞一次即可;也可以自己對(duì)kv存儲(chǔ)里的消息做監(jiān)控,如果超過一定時(shí)長(zhǎng)沒收到ack伐谈,就主動(dòng)重發(fā)消息烂完。

大家看看下面的圖,一起來(lái)體會(huì)一下:

6

消息中間件全鏈路100%數(shù)據(jù)不丟失能做到嗎诵棵?

到此為止抠蚣,我們已經(jīng)把生產(chǎn)端和消費(fèi)端如何保證消息不丟失的相關(guān)技術(shù)方案結(jié)合RabbitMQ這種中間件都給大家分析過了。

其實(shí)履澳,架構(gòu)思想是通用的嘶窄, 無(wú)論你用的是哪一種MQ中間件,他們提供的功能是不太一樣的距贷,但是你都需要考慮如下幾點(diǎn):

生產(chǎn)端如何保證投遞出去的消息不丟失:消息在半路丟失柄冲,或者在MQ內(nèi)存中宕機(jī)導(dǎo)致丟失,此時(shí)你如何基于MQ的功能保證消息不要丟失忠蝗?

MQ自身如何保證消息不丟失:起碼需要讓MQ對(duì)消息是有持久化到磁盤這個(gè)機(jī)制现横。

消費(fèi)端如何保證消費(fèi)到的消息不丟失:如果你處理到一半消費(fèi)端宕機(jī),導(dǎo)致消息丟失阁最,此時(shí)怎么辦戒祠?

目前來(lái)說,我們初步的借著RabbitMQ舉例速种,已經(jīng)把從前到后一整套技術(shù)方案的原理姜盈、設(shè)計(jì)和實(shí)現(xiàn)都給大家分析了一遍了。

但是此時(shí)真的能做到100%數(shù)據(jù)不丟失嗎配阵?恐怕未必馏颂,大家再考慮一下個(gè)特殊的場(chǎng)景。

生產(chǎn)端投遞了消息到MQ棋傍,而且持久化到磁盤并且回傳ack給生產(chǎn)端了救拉。

但是此時(shí)MQ還沒投遞消息給消費(fèi)端,結(jié)果MQ部署的機(jī)器突然宕機(jī)舍沙,而且因?yàn)槲粗脑虼疟P損壞了近上,直接在物理層面導(dǎo)致MQ持久化到磁盤的數(shù)據(jù)找不回來(lái)了。

這個(gè)大家千萬(wàn)別以為是開玩笑的拂铡,大家如果留意留意行業(yè)新聞壹无,這種磁盤損壞導(dǎo)致數(shù)據(jù)丟失的是真的有的。

那么此時(shí)即使你把MQ重啟了感帅,磁盤上的數(shù)據(jù)也丟失了斗锭,數(shù)據(jù)是不是還是丟失了?

你說失球,我可以用MQ的集群機(jī)制啊岖是,給一個(gè)數(shù)據(jù)做多個(gè)副本帮毁,比如后面我們就會(huì)給大家分析RabbitMQ的鏡像集群機(jī)制,確實(shí)可以做到數(shù)據(jù)多副本豺撑。

但是即使數(shù)據(jù)多副本烈疚,一定可以做到100%數(shù)據(jù)不丟失?

比如說你的機(jī)房突然遇到地震聪轿,結(jié)果機(jī)房里的機(jī)器全部沒了爷肝,數(shù)據(jù)是不是還是全丟了?

說這個(gè)陆错,并不是說要抬杠灯抛。而是告訴大家,技術(shù)這個(gè)東西音瓷,100%都是理論上的期望对嚼。

應(yīng)該說,我們凡事都朝著100%去做绳慎,但是理論上是不可能完全做到100%保證的纵竖,可能就是做到99.9999%的可能性數(shù)據(jù)不丟失,但是還是有千萬(wàn)分之一的概率會(huì)丟失杏愤。

當(dāng)然磨确,從實(shí)際的情況來(lái)說,能做到這種地步声邦,其實(shí)基本上已經(jīng)基本數(shù)據(jù)不會(huì)丟失了。

如果想學(xué)習(xí)Java工程化摆舟、高性能及分布式亥曹、深入淺出。微服務(wù)恨诱、Spring媳瞪,MyBatis,Netty源碼分析的朋友可以加我的Java高級(jí)交流:787707172照宝,群里有阿里大牛直播講解技術(shù)蛇受,以及Java大型互聯(lián)網(wǎng)技術(shù)的視頻免費(fèi)分享給大家。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厕鹃,一起剝皮案震驚了整個(gè)濱河市兢仰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剂碴,老刑警劉巖把将,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異忆矛,居然都是意外死亡察蹲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)洽议,“玉大人宗收,你說我怎么就攤上這事⊙切郑” “怎么了混稽?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)儿捧。 經(jīng)常有香客問我荚坞,道長(zhǎng),這世上最難降的妖魔是什么菲盾? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任颓影,我火速辦了婚禮,結(jié)果婚禮上懒鉴,老公的妹妹穿的比我還像新娘诡挂。我一直安慰自己,他們只是感情好临谱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布璃俗。 她就那樣靜靜地躺著,像睡著了一般悉默。 火紅的嫁衣襯著肌膚如雪城豁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天抄课,我揣著相機(jī)與錄音唱星,去河邊找鬼。 笑死跟磨,一個(gè)胖子當(dāng)著我的面吹牛间聊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抵拘,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哎榴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了僵蛛?” 一聲冷哼從身側(cè)響起尚蝌,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎充尉,沒想到半個(gè)月后驼壶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喉酌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年热凹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泵喘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡般妙,死狀恐怖纪铺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碟渺,我是刑警寧澤鲜锚,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站苫拍,受9級(jí)特大地震影響芜繁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绒极,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一骏令、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垄提,春花似錦榔袋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至审丘,卻和暖如春吏够,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背滩报。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工稿饰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人露泊。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像旅择,于是被迫代替她去往敵國(guó)和親惭笑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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