面試官靈魂暴擊:如何保障消息100%投遞成功?如何保證消息冪等性?
“今天無聊帶你們撩一下消息的可靠性傳輸和冪等性
可能出現(xiàn)消息丟失的情況?
Producer在把Message發(fā)送Broker的過程中,因?yàn)榫W(wǎng)絡(luò)問題等發(fā)生丟失,或者M(jìn)essage到了Broker,但是出了問題,沒有保存下來
“針對(duì)這個(gè)問題,Producer可以開啟MQ的事務(wù),如果這個(gè)過程出現(xiàn)異常,進(jìn)行回滾,但是有個(gè)很大的問題,你提交一個(gè)事務(wù)就會(huì)阻塞在那,非常影響性能,生產(chǎn)環(huán)境肯定不會(huì)開啟事務(wù),一般都是使用confirm機(jī)制
Broker接收到Message暫存到內(nèi)存,Consumer還沒來得及消費(fèi),Broker掛掉了
“可以通過持久化設(shè)置去解決:(1) 創(chuàng)建Queue的時(shí)候設(shè)置持久化,保證Broker持久化Queue的元數(shù)據(jù),但是不會(huì)持久化Queue里面的消息; (2) 將Message的deliveryMode設(shè)置為2,可以將消息持久化到磁盤,這樣只有Message支持化到磁盤之后才會(huì)發(fā)送通知Producer ack。
這兩步過后,即使Broker掛了,Producer肯定收不到ack的,就可以進(jìn)行重發(fā)。
Consumer有消費(fèi)到Message,但是內(nèi)部出現(xiàn)問題,Message還沒處理,Broker以為Consumer處理完了,只會(huì)把后續(xù)的消息發(fā)送
“這時(shí)候,就要關(guān)閉autoack,消息處理過后,進(jìn)行手動(dòng)ack
生產(chǎn)端如何保證可靠性投遞?
保證消息的成功發(fā)出
保證MQ節(jié)點(diǎn)的成功接收
發(fā)送端收到MQ節(jié)點(diǎn)(Broker)的確認(rèn)應(yīng)答
完善的消息補(bǔ)償機(jī)制
解決方案
消息落庫
消息落庫,對(duì)消息狀態(tài)進(jìn)行變更,對(duì)于高并發(fā)環(huán)境下數(shù)據(jù)庫壓力很大,因?yàn)樾枰獙懚啻螖?shù)據(jù)庫 
整體流程:
業(yè)務(wù)數(shù)據(jù)和消息都進(jìn)行落庫
生產(chǎn)端發(fā)送message給Broker
Broker給Confirm響應(yīng)返回生產(chǎn)端
接收到confirm,對(duì)message狀態(tài)更改
分布式定時(shí)任務(wù)獲取消息的狀態(tài)
如果消息不能成功投遞,重新進(jìn)行發(fā)送,記錄重發(fā)次數(shù)
當(dāng)重發(fā)3次之后,將狀態(tài)修改,只能人工進(jìn)行干預(yù)
消息的延遲投遞
消息的延遲投遞,做二次確認(rèn),回調(diào)檢查。適合高并發(fā)環(huán)境,減少寫庫的次數(shù)

整體流程:
上游服務(wù)首先將業(yè)務(wù)代碼入庫,發(fā)送message給Broker
發(fā)送第二個(gè)延遲確認(rèn)消息
下游服務(wù)監(jiān)聽消息進(jìn)行消費(fèi)
發(fā)送確認(rèn)消息,這里不是confirm機(jī)制,而是一條新的消息
通過回調(diào)服務(wù)監(jiān)聽這個(gè)confirm消息,然后把消息進(jìn)行入庫
回調(diào)服務(wù)檢查到延遲確認(rèn)消息,會(huì)在數(shù)據(jù)庫查詢是否有這條消息
如果沒有查到這條消息,回調(diào)服務(wù)通過RPC給一個(gè)重新發(fā)送命令到上游系統(tǒng)
“相比第一種方案,這里減少了一次message入庫,confirm機(jī)制是消息可靠性投遞的一個(gè)核心。
RabbitMQ可能導(dǎo)致出現(xiàn)非冪等性的情況
可靠性消息投遞機(jī)制:consumer回復(fù)confirm出現(xiàn)網(wǎng)絡(luò)閃斷,producer沒有收到ack,定時(shí)任務(wù)輪詢可能就會(huì)重新發(fā)送消息,這樣consumer就會(huì)收到兩條消息
MQ Broker與消費(fèi)端傳輸消息的過程出現(xiàn)網(wǎng)絡(luò)抖動(dòng)
消費(fèi)端故障或異常
kafka可能出現(xiàn)非冪等性的情況

在Consumer端offset沒有提交的時(shí)候,Consumer重啟了,這時(shí)候就會(huì)出現(xiàn)重復(fù)消費(fèi)的情況
解決方案
唯一ID+指紋碼
整體實(shí)現(xiàn)相對(duì)簡單,需要進(jìn)行數(shù)據(jù)庫寫入,利用數(shù)據(jù)庫主鍵去重,使用ID進(jìn)行分庫分表算法路由,從單庫的冪等性到多庫的冪等性
這里唯一ID一般就是業(yè)務(wù)表的主鍵,比如商品ID 指紋碼:每次操作都要生成指紋碼,可以用時(shí)間戳+業(yè)務(wù)編號(hào)+...組成,目的是保證每次操作都是正常的

整體流程:
需要一個(gè)統(tǒng)一ID生成服務(wù),為了保證可靠性,上游服務(wù)也要有個(gè)本地ID生成服務(wù),然后發(fā)送消息給Broker 需要ID規(guī)則路由組件去監(jiān)聽消息,先入庫,如果入庫成功,證明沒有重復(fù),然后發(fā)給下游,如果發(fā)現(xiàn)庫里面有了這條消息,就不發(fā)給下游
— 【 THE END 】— 本公眾號(hào)全部博文已整理成一個(gè)目錄,請?jiān)诠娞?hào)里回復(fù)「m」獲取! 最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) PDF 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。
謝謝支持喲 (*^__^*)
