RabbitMQ如何保證消息的可靠性
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質(zhì)文章,第一時間送達
1、保證消息不丟失(三步)
1.1、開啟事務(wù)(不推薦)
1.2、開啟confirm(推薦)
1.3、開啟RabbitMQ持久化(交換機、隊列、消息)
1.4、關(guān)閉RabbitMQ自動ack(改成手動)
2、保證消息不重復(fù)消費
2.1、冪等性(每個消息用一個唯一標識來區(qū)分,消費前先判斷標識有沒有被消費過,若已消費過,則直接ACK)
3、RabbitMQ如何保證消息的順序性
將消息放入同一個交換機,交給同一個隊列,這個隊列只有一個消費者,消費者只允許同時開啟一個線程
4、RabbitMQ消息重試機制
消費者在消費消息的時候,如果消費者業(yè)務(wù)邏輯出現(xiàn)程序異常,這時候應(yīng)該如何處理?
答案:使用消息重試機制(SpringBoot默認3次消息重試機制)
如何合適選擇重試機制
消費者取到消息后,調(diào)用第三方接口,接口無法訪問,需要使用重試機制
消費者取到消息后,拋出數(shù)據(jù)轉(zhuǎn)換異常,不需要重試機制,需要發(fā)布者進行解決。
5、SpringBoot消息重試機制
@EnableRetry注解:表示啟用重試機制(value表示哪些異常需要觸發(fā)重試,maxAttempts設(shè)置最大重試次數(shù),delay表示重試的延遲時間,multiplier表示上一次延時時間是這一次的倍數(shù))
eg、@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
@Recover注解:當重試次數(shù)達到設(shè)置的最大次數(shù)的時候,程序還是執(zhí)行異常,調(diào)用的回調(diào)函數(shù)。
6、RabbitMQ死信隊列
死信隊列是當消息在一個隊列因為下列原因:
a、消息被拒絕(basic.reject或basic.nack)并且requeue=false.
b、消息TTL過期
c、隊列達到最大長度(隊列滿了,數(shù)據(jù)無法添加到mq中)
變成了 “死信隊列” 后被重新投遞(publish)到另一個Exchange,然后重新消費。說白了就是沒有被消費的消息換個地方重新被消費
7、RabbitMQ解決分布式事務(wù)
經(jīng)典案例,以目前流行的外賣為例,用戶下單后,調(diào)用訂單服務(wù),訂單服務(wù)調(diào)用派單系統(tǒng)通知送外賣人員送單,這時候訂單系統(tǒng)與派單系統(tǒng)采用MQ異步通訊。
RabbitMQ解決分布式事務(wù)原理
答案:采用最終一致性原理
需要保證以下三要素:
a、確保生產(chǎn)者一定要將數(shù)據(jù)投遞到MQ服務(wù)器中(采用MQ消息確認機制)
b、確保消費者能夠正確消費消息,采用手動ACK模式(注意重試、冪等性問題)
c、如何保證第一個事務(wù)先執(zhí)行,采用補償機制,在創(chuàng)建一個補單消費者進行監(jiān)聽,如果訂單沒有創(chuàng)建成功,進行補單。(如果第一個事務(wù)中出錯,補單消費者會在重新執(zhí)行一次第一個事務(wù),例如第一個事務(wù)是添加訂單表,如果失敗在補單的時候重新生成訂單記錄,由于訂單號唯一,所以不會重復(fù))
8、RabbitMQ保證消息不丟失的具體方案
前提:
(1)開啟confirm
(2)開啟RabbitMQ的持久化(交換機、隊列、消息)
(3)關(guān)閉RabbitMQ的自動ack(改成手動)
(4)配置消費重試次數(shù),消費重試間隔時間等
涉及到的技術(shù)點:
MQ、Redis、定時任務(wù)
8.1、保證投放消息不丟失
(1)先將消息放入生產(chǎn)者Redis(此時消息的狀態(tài)為未投放),再放入隊列
(2)根據(jù)confirm(ReturnCallback和ConfirmCallback)的結(jié)果來確定消息是否投遞成功,
投遞成功的,修改生產(chǎn)者redis中消息的投遞狀態(tài)為已投遞
投遞失敗的消息將會放入失敗的Redis,并從生產(chǎn)者Redis中刪除,由定時任務(wù)定期掃描并重新投遞
(3)生產(chǎn)者Redis定時任務(wù)
生產(chǎn)者Redis定時任務(wù)專門掃描生產(chǎn)者Redis中存放了一定時間,但是狀態(tài)還是未投放的消息
此消息會被認為已經(jīng)投遞,但是沒有任何反饋結(jié)果(由于不可知因素,導致沒有ReturnCallback,也沒有ConfirmCallback),
此類消息被掃描到后,會放入失敗的Redis,并從生產(chǎn)者Redis中刪除,由定時任務(wù)定期掃描并重新投遞
(4)還需要一個專門的定時任務(wù)掃描生產(chǎn)者Redis中存放了很久,仍然未消費的數(shù)據(jù)(狀態(tài)為已投遞),此類消息被掃描到后,會放入失敗的Redis,并從生產(chǎn)者Redis中刪除,由定時任務(wù)定期掃描并重新投遞
(5)掃描失敗的Redis的定時任務(wù)都遵循一條原則,一條消息最多被重新投遞三次,若投遞了三次仍然失敗,則記錄日志,記錄到數(shù)據(jù)庫,不會再投遞,需要人工干預(yù)處理
8.2、保證消費消息不丟失
(1)消費者取到消息后,從消息中取出唯一標識,先判斷此消息有沒有被消費過,若已消費過,則直接ACK(避免重復(fù)消費)
(2)正常處理成功后,將生產(chǎn)者Redis中的此消息刪除,并ACK(告訴server端此消息已成功消費)
(3)遇到異常時,捕獲異常,驗證自己在消息中設(shè)定的重試次數(shù)是否超過閥值,若超過,則放入死信隊列,若未超過,則向?qū)⑾⒅械闹卦嚧螖?shù)加1,拋出自定義異常,進入重試機制
(4)有專門的消費者用于處理死信隊列中消費多次仍未消費成功的數(shù)據(jù),可以記錄日志,入庫,人工干預(yù)處理
作者 | Ruthless
來源 | cnblogs.com/linjiqin/p/12683076.html

