消息可靠性投遞
可靠性投遞需滿足四個(gè)條件:
1.保障消息的成功發(fā)出
2.保障MQ節(jié)點(diǎn)的成功接收
3.發(fā)送端收到MQ節(jié)點(diǎn)(Broker)確認(rèn)應(yīng)答
4.完善的消息進(jìn)行補(bǔ)償機(jī)制
臨界值情況:
情況一:生產(chǎn)端投遞消息失敗页衙,消費(fèi)端未收到消息杀怠。
情況二:生產(chǎn)端投遞消息了,消費(fèi)端也收到了吴菠,但在返回應(yīng)答過程中橄教,突然網(wǎng)絡(luò)中斷了導(dǎo)致發(fā)送端未收到確認(rèn)應(yīng)答清寇。
可靠性投遞解決方案
第一種方案:消息落庫,對(duì)消息狀態(tài)進(jìn)行打標(biāo)护蝶。
在發(fā)送消息時(shí)华烟,要將消息持久化到數(shù)據(jù)庫中,然后消息設(shè)置一個(gè)狀態(tài)滓走,如發(fā)送出去垦江,狀態(tài)為0(發(fā)送中),消息到達(dá)broker端搅方,broker端返回響應(yīng)后比吭,將消息狀態(tài)變更為1(消息已成功收到)。
但是姨涡,針對(duì)沒有收到響應(yīng)的消息衩藤,該怎么做?做一個(gè)輪詢操作涛漂,抓取一些沒有OK的消息赏表,設(shè)置最大嘗試次數(shù),進(jìn)行重新發(fā)送匈仗。
第二種方案:消息的延遲投遞瓢剿,做二次確認(rèn),回調(diào)檢查悠轩。
消息落庫方案
1.消息落庫间狂。分為兩個(gè)小步驟,一個(gè)是訂單業(yè)務(wù)數(shù)據(jù)落庫火架,一個(gè)是訂單message落庫鉴象。因此忙菠,第一件事情把訂單業(yè)務(wù)數(shù)據(jù)入庫(創(chuàng)建訂單實(shí)體),第二件事情要生產(chǎn)一條消息纺弊,將message封裝好牛欢,然后把這條消息也要入庫,設(shè)置消息初始狀態(tài)0淆游,表示消息發(fā)送中傍睹。這種方式缺點(diǎn)在于要對(duì)數(shù)據(jù)庫數(shù)據(jù)持久化兩次。這里必須保證這兩步持久化操作成功稽犁,否則立即返回快速失敗焰望。
2.發(fā)送消息給broker
3.假設(shè)broker收到消息,broker將應(yīng)答給生產(chǎn)端已亥。
4.producer端會(huì)有個(gè)Confirm Listener異步的監(jiān)聽broker端返回的響應(yīng)熊赖。如果broker端返回true,監(jiān)聽器監(jiān)聽到true后虑椎,會(huì)將這條指定的消息狀態(tài)更新為1震鹉,表示這條消息已經(jīng)百分之百的投遞成功了。
5.分布式定時(shí)任務(wù)捆姜,處理極端情況传趾。假設(shè)broker端在回送響應(yīng)時(shí),網(wǎng)絡(luò)突然間閃斷泥技,這是MSG DB中這條消息永遠(yuǎn)是初始狀態(tài)0浆兰。這個(gè)時(shí)候需要設(shè)定一個(gè)規(guī)則,設(shè)置一個(gè)臨界值timeout珊豹,比如5分鐘簸呈,如果消息5分鐘之內(nèi)還是初始狀態(tài)0,就需要將這條消息抽取出來店茶,執(zhí)行
6.重新發(fā)送蜕便。或者定時(shí)任務(wù)設(shè)置一個(gè)定時(shí)間隔贩幻,如每隔5分鐘抓取一次status為0的訂單轿腺,這種可能會(huì)出現(xiàn)一個(gè)小問題,消息剛發(fā)出去丛楚,定時(shí)任務(wù)就開始跑了族壳,有一些消息其實(shí)是能ACK成功的,但是分布式定時(shí)任務(wù)又重發(fā)了一遍趣些。所以建議是設(shè)置一個(gè)消息超時(shí)的最大時(shí)間限制仿荆,如5分鐘之內(nèi)這條線消息還沒有收到broker端的響應(yīng),status還是0,這個(gè)時(shí)候赖歌,再去抽取出來,再執(zhí)行第六步重新發(fā)送功茴。第六步:重新發(fā)送
7.設(shè)置最大重試次數(shù)庐冯,超過最大重試次數(shù),將status更新為2表示投遞失敗坎穿。
消息的延遲投遞, 做二次確認(rèn), 回調(diào)檢查
1. 第一次消息發(fā)送消息A必須業(yè)務(wù)數(shù)據(jù)落庫之后才能進(jìn)行消息發(fā)送
2.第二次消息延遲發(fā)送, 設(shè)定延遲一段時(shí)間發(fā)送第二次驗(yàn)證消息B
3.消費(fèi)端監(jiān)聽Broker, 進(jìn)行消息消費(fèi)展父,消費(fèi)消息A
4.消費(fèi)成功之后, 發(fā)送確認(rèn)消息C到確認(rèn)消息隊(duì)列
5. Callback Service監(jiān)聽step4中的確認(rèn)消息隊(duì)列, 接收確認(rèn)消息C,存儲(chǔ)到數(shù)據(jù)庫
6.Callback Service監(jiān)聽step2發(fā)送的Delay Check的消息隊(duì)列, 收到延時(shí)消息B之后玲昧,檢測(cè)數(shù)據(jù)庫是否存儲(chǔ)
7.如果數(shù)據(jù)庫沒有存儲(chǔ)栖茉,重新走該流程
消息冪等性
消息冪等性,其實(shí)就是保證同一個(gè)消息不被消費(fèi)者重復(fù)消費(fèi)兩次孵延。當(dāng)消費(fèi)者消費(fèi)完消息之后吕漂,通常會(huì)發(fā)送一個(gè)ack應(yīng)答確認(rèn)信息給生產(chǎn)者,但是這中間有可能因?yàn)榫W(wǎng)絡(luò)中斷等原因尘应,導(dǎo)致生產(chǎn)者未能收到確認(rèn)消息惶凝,由此這條消息將會(huì)被 重復(fù)發(fā)送給其他消費(fèi)者進(jìn)行消費(fèi),實(shí)際上這條消息已經(jīng)被消費(fèi)過了犬钢,這就是重復(fù)消費(fèi)的問題苍鲜。
實(shí)現(xiàn)消息冪等性
消息全局ID或者寫個(gè)唯一標(biāo)識(shí)(如時(shí)間戳、UUID等) :每次消費(fèi)消息之前根據(jù)消息id去判斷該消息是否已消費(fèi)過玷犹,如果已經(jīng)消費(fèi)過混滔,則不處理這條消息,否則正常消費(fèi)消息歹颓,并且進(jìn)行入庫操作坯屿。(消息全局ID作為數(shù)據(jù)庫表的主鍵,防止重復(fù))
利用Redis的分布式鎖:給消息分配一個(gè)全局ID晴股,只要消費(fèi)過該消息愿伴,將 < id,message>寫入redis,消費(fèi)者開始消費(fèi)前电湘,先去redis中查詢有沒消費(fèi)記錄即可隔节。
消息有序性
RabbitMQ在2.7.0及之后版本支持【同發(fā)送信道、同exchange寂呛、同queue怎诫、同消費(fèi)信道的消息順序與發(fā)送順序相同】
一句話總結(jié):單一生產(chǎn)者、單一隊(duì)列贷痪、單一消費(fèi)進(jìn)程是可以保障有序的幻妓,其他不保證