6.RabbitMQ 可靠性投遞與高可用架構(gòu)

1.可靠性投遞

1)簡述分析

1.可靠性投遞:也就是在使用 RabbitMQ 實現(xiàn)異步通信的時候搀愧,消息丟了怎么辦入偷,消息重復消費怎么辦?

2.明確一個問題:因為效率與可靠性是無法兼得的追驴,如果要保證每一個環(huán)節(jié)都成功,勢必會對消息的收發(fā)效率造成影響疏之。所以如果是一些業(yè)務實時一致性要求不是特別高的場合殿雪,可以犧牲一些可靠性來換取效率。比如發(fā)送通知或者記錄日志的這種場景体捏,如果用戶沒有收到通知冠摄,不會造成業(yè)務影響,只要再次發(fā)送就行了几缭。

3.可靠性保證的環(huán)節(jié)

RabbitMQ 的工作模型

1.代表消息從生產(chǎn)者發(fā)送到 Broker:生產(chǎn)者把消息發(fā)到 Broker 之后河泳,怎么知道自己的消息有沒有被 Broker 成功接收?

2.代表消息從 Exchange 路由到 Queue:Exchange 是一個綁定列表,如果消息沒有辦法路由到正確的隊列年栓,會發(fā)生什么事情?應該怎么處理?

3.代表消息在 Queue 中存儲:隊列是一個獨立運行的服務拆挥,有自己的數(shù)據(jù)庫(Mnesia),它是真正用來存儲消息的某抓。如果還沒有消費者來消費纸兔,那么消息要一直存儲在隊列里面。如果隊列出了問題否副,消息肯定會丟失汉矿。怎么保證消息在隊列穩(wěn)定地存儲呢?

4.代表消費者訂閱 Queue 并消費消息:隊列的特性是什么?FIFO。隊列里面的消息是一條一條的投遞的备禀,也就是說洲拇,只有上一條消息被消費者接收以后,才能把這一條消息從數(shù)據(jù)庫刪掉曲尸,繼續(xù)投遞下一條消息赋续。那么問題來了,Broker 怎么知道消費者已經(jīng)接收了消息呢?

2)消息發(fā)送到 RabbitMQ 服務器

1.提供機制服務端確認機制另患,也就是在生產(chǎn)者發(fā)送消息給RabbitMQ 的服務端的時候纽乱,服務端會通過某種方式返回一個應答,只要生產(chǎn)者收到了這個應答昆箕,就知道消息發(fā)送成功了鸦列。

2.服務端確認機制-事務模式

1)事務模式怎么使用:我們通過一個 channel.txSelect()的方法把信道設置成事務模式,然后就可以發(fā)布消息給 RabbitMQ 了鹏倘,如果 channel.txCommit();的方法調(diào)用成功敛熬,就說明事務提交成功,則消息一定到達了 RabbitMQ 中第股。如果在事務提交執(zhí)行之前由于 RabbitMQ 異常崩潰或者其他原因拋出異常应民,這個時候我們便可以將其捕獲,進而通過執(zhí)行 channel.txRollback()方法來實現(xiàn)事務回滾。

事務確認機制圖

2)缺點:在事務模式里面诲锹,只有收到了服務端的 Commit-OK 的指令繁仁,才能提交成功。所以可以解決生產(chǎn)者和服務端確認的問題归园。但是事務模式有一個缺點黄虱,它是阻塞的,一條消息沒有發(fā)送完畢庸诱,不能發(fā)送下一條消息捻浦,它會榨干 RabbitMQ 服務器的性能。所以不建議大家在生產(chǎn)環(huán)境使用桥爽。

3)Spring Boot 中的設置

SpringBoot

3)服務端確認機制-Confirm(確認)模式

1.普通確認模式:在生產(chǎn)者這邊通過調(diào)用 channel.confirmSelect()方法將信道設置為 Confirm 模式朱灿,然后發(fā)送消息。一旦消息被投遞到所有匹配的隊列之后钠四,RabbitMQ 就會發(fā)送一個確認(Basic.Ack)給生產(chǎn)者盗扒,也就是調(diào)用 channel.waitForConfirms()返回 true,這樣生產(chǎn)者就知道消息被服務端接收了缀去!----》方式消息效率還不是太高

2.批量確認模式:批量確認侣灶,就是在開啟 Confirm 模式后,先發(fā)送一批消息缕碎。只要channel.waitForConfirmsOrDie();方法沒有拋出異常褥影,就代表消息都被服務端接收了。

批量確認的方式比單條確認的方式效率要高咏雌,但是也有兩個問題伪阶,第一個就是批量的數(shù)量的確定。對于不同的業(yè)務处嫌,到底發(fā)送多少條消息確認一次?數(shù)量太少,效率提升不上去斟湃。數(shù)量多的話熏迹,又會帶來另一個問題,比如我們發(fā) 1000 條消息才確認一次凝赛,如果前面 999 條消息都被服務端接收了注暗,如果第 1000 條消息被拒絕了,那么前面所有的消息都要重發(fā)墓猎。

3.異步確認模式:一邊發(fā)送一邊確認捆昏!異步確認模式需要添加一個 ConfirmListener,并且用一個 SortedSet 來維護沒有被確認的消息毙沾。Confirm 模式是在 Channel 上開啟的骗卜,因為 RabbitTemplate 對 Channel 進行了封裝,叫做 ConfimrCallback

異步確認

3)消息從交換機路由到隊列

1.在什么情況下寇仓,消息會無法路由到正確的隊列?可能因為路由鍵錯誤举户,或者隊列不存在。

2.兩種方式處理無法路由的消息:一種就是讓服務端重發(fā)給生產(chǎn)者遍烦,一種是讓交換機路由到另一個備份的交換機俭嘁。

3.消息回發(fā)的方式:使用 mandatory 參數(shù)和 ReturnListener(在 Spring AMQP 中是ReturnCallback)。

處理路由-消息回發(fā)

4.備份交換機的方式:在創(chuàng)建交換機的時候服猪,從屬性中指定備份交換機供填。

處理路由-備份交換機

5.注意區(qū)別:隊列可以指定死信交換機;交換機可以指定備份交換機!

4)消息在隊列存儲

1.問題:如果 RabbitMQ 的服務或者硬件發(fā)生故障,比如系統(tǒng)宕機罢猪、重啟近她、關閉等等,可能會導致內(nèi)存中的消息丟失坡脐,所以我們要把消息本身和元數(shù)據(jù)(隊列泄私、交換機、綁定)都保存到磁盤备闲。

2.解決方案:1)隊列持久化 2)交換機持久化 3)消息持久化 4)集群

隊列持久化
交換機持久化
消息持久化

集群:如果只有一個 RabbitMQ 的節(jié)點晌端,即使交換機、隊列恬砂、消息做了持久化咧纠,如果服務崩潰或者硬件發(fā)生故障,RabbitMQ 的服務一樣是不可用的泻骤,所以為了提高 MQ 服務的可用性漆羔,保障消息的傳輸,我們需要有多個 RabbitMQ 的節(jié)點狱掂!

5)消息投遞到消費者

1.問題:如果消費者收到消息后沒來得及處理即發(fā)生異常演痒,或者處理過程中發(fā)生異常,會導致4失敗趋惨。服務端應該以某種方式得知消費者對消息的接收情況鸟顺,并決定是否重新投遞這條消息給其他消費者。

2.解決方案:RabbitMQ 提供了消費者的消息確認機制(message acknowledgement)器虾,消費者可以自動或者手動地發(fā)送 ACK 給服務端讯嫂。沒有收到 ACK 的消息,消費者斷開連接后兆沙,RabbitMQ 會把這條消息發(fā)送給其他消費者欧芽。如果沒有其他消費者,消費者重啟后會重新消費這條消息葛圃,重復執(zhí)行業(yè)務邏輯千扔。

3.指定參數(shù):消費者在訂閱隊列時憎妙,可以指定 autoAck 參數(shù),當 autoAck 等于 false 時昏鹃,RabbitMQ會等待消費者顯式地回復確認信號后才從隊列中移去消息尚氛。

4.如何設置手動 ACK?

設置手動

5.三個值的區(qū)別:?NONE:自動 ACK? ?MANUAL: 手動 ACK? ?AUTO:如果方法未拋出異常,則發(fā)送 ack洞渤。

6.auto注意:如果方法未拋出異常阅嘶,則發(fā)送 ack!當拋出 AmqpRejectAndDontRequeueException 異常的時候载迄,則消息會被拒絕讯柔,且不重新入隊。當拋出 ImmediateAcknowledgeAmqpException 異常护昧,則消費者會發(fā)送 ACK魂迄。其他的異常,則消息會被拒絕惋耙,且 requeue = true 會重新入隊捣炬。

7. Spring Boot 中,消費者又怎么調(diào)用 ACK绽榛,或者說怎么獲得 Channel 參數(shù)呢?

SpringBoot中怎么使用

8.拒絕的方式:Basic.Reject()拒絕單條湿酸,Basic.Nack()批量拒絕。如果 requeue 參數(shù)設置為 true灭美,可以把這條消息重新存入隊列推溃,以便發(fā)給下一個消費者(當然,只有一個消費者的時候届腐,這種方式可能會出現(xiàn)無限循環(huán)重復消費的情況铁坎。可以投遞到新的隊列中犁苏,或者只打印異常日志)硬萍。

6)消費者回調(diào)

1.調(diào)用生產(chǎn)者 API:例如:提單系統(tǒng)給其他系統(tǒng)發(fā)送了碎屏保消息后,其他系統(tǒng)必須在處理完消息后調(diào)用提單系統(tǒng)提供的 API围详,來修改提單系統(tǒng)中數(shù)據(jù)的狀態(tài)朴乖。只要 API 沒有被調(diào)用,數(shù)據(jù)狀態(tài)沒有被修改短曾,提單系統(tǒng)就認為下游系統(tǒng)沒有收到這條消息。

2.發(fā)送響應消息給生產(chǎn)者:例如:商業(yè)銀行與人民銀行二代支付通信赐劣,無論是人行收到了商業(yè)銀行的消息嫉拐,還是商業(yè)銀行收到了人行的消息,都必須發(fā)送一條響應消息(叫做回執(zhí)報文)魁兼。

7)補償機制

1.問題:如果生產(chǎn)者的 API 就是沒有被調(diào)用婉徘,也沒有收到消費者的響應消息漠嵌,怎么辦?

2.解決方案:設置超時時間

8)消息冪等性

1.消息出現(xiàn)重復可能會有兩個原因:1).生產(chǎn)者的問題,環(huán)節(jié)1重復發(fā)送消息盖呼,比如在開啟了 Confirm 模式但未收到確認儒鹿,消費者重復投遞。2).環(huán)節(jié)4出了問題几晤,由于消費者未發(fā)送 ACK 或者其他原因约炎,消息重復投遞。3)生產(chǎn)者代碼或者網(wǎng)絡問題蟹瘾。

2.解決方案:對于重復發(fā)送的消息圾浅,可以對每一條消息生成一個唯一的業(yè)務 ID,通過日志或者消息落庫來做重復控制憾朴。

9)最終一致

1.如果確實是消費者宕機了狸捕,或者代碼出現(xiàn)了 BUG 導致無法正常消費,在我們嘗試多次重發(fā)以后众雷,消息最終也沒有得到處理灸拍,怎么辦?

例如存款的場景,客戶的錢已經(jīng)被吞了砾省,但是余額沒有增加鸡岗,這個時候銀行出現(xiàn)了長款,應該怎么處理?如果客戶沒有主動通知銀行纯蛾,這個問題是怎么發(fā)現(xiàn)的?銀行最終怎么把這個賬務做平?

在我們的金融系統(tǒng)中纤房,都會有雙方對賬或者多方對賬的操作,通常是在一天的業(yè)務結(jié)束之后翻诉,第二天營業(yè)之前炮姨。我們會約定一個標準,比如 ATM 跟核心系統(tǒng)對賬碰煌,肯定是以核心系統(tǒng)為準舒岸。ATMC 獲取到核心的對賬文件,然后解析芦圾,登記成數(shù)據(jù)蛾派,然后跟自己記錄的流水比較,找出核心有 ATM 沒有个少,或者 ATM 有核心沒有洪乍,或者兩邊都有但是金額不一致的數(shù)據(jù)。對賬之后夜焦,我們再手工平賬壳澳。比如取款記了賬但是沒吐鈔的,做一筆沖正茫经。存款吞了鈔沒記賬的巷波,要么把錢退給客戶萎津,要么補一筆賬。

10)消息的順序性

1.定義:消息的順序性指的是消費者消費消息的順序跟生產(chǎn)者生產(chǎn)消息的順序是一致的抹镊。

2.舉例:商戶信息同步到其他系統(tǒng)锉屈,有三個業(yè)務操作:1、新增門店 2垮耳、綁定產(chǎn)品 3颈渊、激活門店,這種情況下消息消費順序不能顛倒(門店不存在時無法綁定產(chǎn)品和激活)氨菇。

3.現(xiàn)狀:在 RabbitMQ 中儡炼,一個隊列有多個消費者時,由于不同的消費者消費消息的速度是不一樣的查蓉,順序無法保證乌询。只有一個隊列僅有一個消費者的情況才能保證順序消費(不同的業(yè)務消息發(fā)送到不同的專用的隊列)。

生產(chǎn)者消費者一一對應
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豌研,一起剝皮案震驚了整個濱河市妹田,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鹃共,老刑警劉巖鬼佣,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異霜浴,居然都是意外死亡晶衷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門阴孟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晌纫,“玉大人,你說我怎么就攤上這事永丝∏率” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵慕嚷,是天一觀的道長哥牍。 經(jīng)常有香客問我,道長喝检,這世上最難降的妖魔是什么嗅辣? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮挠说,結(jié)果婚禮上澡谭,老公的妹妹穿的比我還像新娘。我一直安慰自己纺涤,他們只是感情好译暂,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著撩炊,像睡著了一般外永。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拧咳,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天伯顶,我揣著相機與錄音,去河邊找鬼骆膝。 笑死祭衩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的阅签。 我是一名探鬼主播掐暮,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼政钟!你這毒婦竟也來了路克?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤养交,失蹤者是張志新(化名)和其女友劉穎精算,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碎连,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡灰羽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鱼辙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廉嚼。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖座每,靈堂內(nèi)的尸體忽然破棺而出前鹅,到底是詐尸還是另有隱情,我是刑警寧澤峭梳,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布舰绘,位于F島的核電站,受9級特大地震影響葱椭,放射性物質(zhì)發(fā)生泄漏捂寿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一孵运、第九天 我趴在偏房一處隱蔽的房頂上張望秦陋。 院中可真熱鬧,春花似錦治笨、人聲如沸驳概。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顺又。三九已至更卒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間稚照,已是汗流浹背蹂空。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留果录,地道東北人上枕。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像弱恒,于是被迫代替她去往敵國和親辨萍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359