0 相關(guān)源碼
1 你將學(xué)到
- 如何保證消息百分百投遞成功
- 冪等性
- 如何避免海量訂單生成時(shí)消息的重復(fù)消費(fèi)
- Confirm確認(rèn)消息、Return返回消息
- 自定義消費(fèi)者
- 消息的ACK與重回隊(duì)列
- 限流
- TTL
- 死信隊(duì)列
2 保證消息的百分百投遞成功
2.1 Producer 的可靠性投遞
2.1.1 要求
- 保證消息的成功發(fā)出
- 保證MQ節(jié)點(diǎn)的成功接收
- 發(fā)送端收到MQ節(jié)點(diǎn)(Broker) 確認(rèn)應(yīng)答
- 完善的消息補(bǔ)償機(jī)制
在實(shí)際生產(chǎn)中下硕,很難保障前三點(diǎn)的完全可靠丁逝,比如在極端的環(huán)境中,生產(chǎn)者發(fā)送消息失敗了梭姓,發(fā)送端在接受確認(rèn)應(yīng)答時(shí)突然發(fā)生網(wǎng)絡(luò)閃斷等等情況霜幼,很難保障可靠性投遞,所以就需要有第四點(diǎn)完善的消息補(bǔ)償機(jī)制誉尖。
2.1.2 解決方案
2.1.2.1 方案一:消息信息落庫(kù),對(duì)消息狀態(tài)進(jìn)行打標(biāo)(常見(jiàn)方案)
將消息持久化到DB并設(shè)置狀態(tài)值,收到Consumer的應(yīng)答就改變當(dāng)前記錄的狀態(tài).
再輪詢(xún)重新發(fā)送沒(méi)接收到應(yīng)答的消息,注意這里要設(shè)置重試次數(shù).
方案流程圖
方案實(shí)現(xiàn)流程
比如我下單成功
step1 - 對(duì)訂單數(shù)據(jù)入BIZ DB訂單庫(kù),并對(duì)因此生成的業(yè)務(wù)消息入MSG DB消息庫(kù)
此處由于采用了兩個(gè)數(shù)據(jù)庫(kù),需要兩次持久化操作,為了保證數(shù)據(jù)的一致性,有人可能就想著采用分布式事務(wù),但在大廠(chǎng)實(shí)踐中,基本都是采用補(bǔ)償機(jī)制!
這里一定要保證step1 中消息都存儲(chǔ)成功了罪既,沒(méi)有出現(xiàn)任何異常情況,然后生產(chǎn)端再進(jìn)行消息發(fā)送。如果失敗了就進(jìn)行快速失敗機(jī)制
對(duì)業(yè)務(wù)數(shù)據(jù)和消息入庫(kù)完畢就進(jìn)入
setp2 - 發(fā)送消息到 MQ 服務(wù)上琢感,如果一切正常無(wú)誤消費(fèi)者監(jiān)聽(tīng)到該消息丢间,進(jìn)入
step3 - 生產(chǎn)端有一個(gè)Confirm Listener
,異步監(jiān)聽(tīng)Broker回送的響應(yīng),從而判斷消息是否投遞成功
- step4 - 如果成功,去數(shù)據(jù)庫(kù)查詢(xún)?cè)撓?并將消息狀態(tài)更新為1
- step5 - 如果出現(xiàn)意外情況,消費(fèi)者未接收到或者 Listener 接收確認(rèn)時(shí)發(fā)生網(wǎng)絡(luò)閃斷驹针,導(dǎo)致生產(chǎn)端的Listener就永遠(yuǎn)收不到這條消息的confirm應(yīng)答了千劈,也就是說(shuō)這條消息的狀態(tài)就一直為0了,這時(shí)候就需要用到我們的分布式定時(shí)任務(wù)來(lái)從 MSG 數(shù)據(jù)庫(kù)抓取那些超時(shí)了還未被消費(fèi)的消息牌捷,重新發(fā)送一遍
此時(shí)我們需要設(shè)置一個(gè)規(guī)則墙牌,比如說(shuō)消息在入庫(kù)時(shí)候設(shè)置一個(gè)臨界值timeout,5分鐘之后如果還是0的狀態(tài)那就需要把消息抽取出來(lái)暗甥。這里我們使用的是分布式定時(shí)任務(wù)喜滨,去定時(shí)抓取DB中距離消息創(chuàng)建時(shí)間超過(guò)5分鐘的且狀態(tài)為0的消息。
step6 - 把抓取出來(lái)的消息進(jìn)行重新投遞(Retry Send)撤防,也就是從第二步開(kāi)始繼續(xù)往下走
step7 - 當(dāng)然有些消息可能就是由于一些實(shí)際的問(wèn)題無(wú)法路由到Broker虽风,比如routingKey設(shè)置不對(duì),對(duì)應(yīng)的隊(duì)列被誤刪除了寄月,那么這種消息即使重試多次也仍然無(wú)法投遞成功辜膝,所以需要對(duì)重試次數(shù)做限制,比如限制3次漾肮,如果投遞次數(shù)大于三次厂抖,那么就將消息狀態(tài)更新為2,表示這個(gè)消息最終投遞失敗,然后通過(guò)補(bǔ)償機(jī)制克懊,人工去處理忱辅。實(shí)際生產(chǎn)中,這種情況還是比較少的谭溉,但是你不能沒(méi)有這個(gè)補(bǔ)償機(jī)制墙懂,要不然就做不到可靠性了。
思考:該方案在高并發(fā)的場(chǎng)景下是否合適
對(duì)于第一種方案扮念,我們需要做兩次數(shù)據(jù)庫(kù)的持久化操作损搬,在高并發(fā)場(chǎng)景下顯然數(shù)據(jù)庫(kù)存在著性能瓶頸.
其實(shí)在我們的核心鏈路中只需要對(duì)業(yè)務(wù)進(jìn)行入庫(kù)就可以了,消息就沒(méi)必要先入庫(kù)了柜与,我們可以做消息的延遲投遞巧勤,做二次確認(rèn),回調(diào)檢查旅挤。下面然我們看方案二
2.1.2.2 消息延遲投遞,兩次確認(rèn),回調(diào)檢查(大規(guī)模海量數(shù)據(jù)方案)
大廠(chǎng)經(jīng)典實(shí)現(xiàn)方案
當(dāng)然這種方案不一定能保障百分百投遞成功踢关,但是基本上可以保障大概99.9%的消息是OK的伞鲫,有些特別極端的情況只能是人工去做補(bǔ)償了粘茄,或者使用定時(shí)任務(wù).
主要就是為了減少DB操作
方案流程圖
- Upstream Service
上游服務(wù),即生產(chǎn)端 - Downstream service
下游服務(wù),即消費(fèi)端 - Callback service
回調(diào)服務(wù)
方案實(shí)現(xiàn)流程
- step1 一定要先將業(yè)務(wù)消息入庫(kù),然后Pro再發(fā)出消息,順序不能錯(cuò)!
- step2 在發(fā)送消息之后,緊接著Pro再發(fā)送一條消息(Second Send Delay Check),即延遲消息投遞檢查,這里需要設(shè)置一個(gè)延遲時(shí)間,比如5分鐘之后進(jìn)行投遞.
- step3 Con監(jiān)聽(tīng)指定的隊(duì)列,處理收到的消息.
- step4 處理完成之后,發(fā)送一個(gè)confirm消息,也就是回送響應(yīng),但是其不是普通的ACK,而是重新生成一條消息,投遞到MQ,表示處理成功.
- Callback service是一個(gè)單獨(dú)的服務(wù),它扮演MSG DB角色,它通過(guò)MQ監(jiān)聽(tīng)下游服務(wù)發(fā)送的confirm消息,如果監(jiān)聽(tīng)到confirm消息,那么就對(duì)其持久化到MSG DB.
- step6 5分鐘之后延遲消息發(fā)送到MQ,然后Callback service還是去監(jiān)聽(tīng)延遲消息所對(duì)應(yīng)的隊(duì)列,收到Check消息后去檢查DB中是否存在消息,如果存在柒瓣,則不需要做任何處理儒搭,如果不存在或者消費(fèi)失敗了,那么Callback service就需要主動(dòng)發(fā)起RPC通信給上游服務(wù)芙贫,告訴它延遲檢查的這條消息我沒(méi)有找到搂鲫,你需要重新發(fā)送,生產(chǎn)端收到信息后就會(huì)重新查詢(xún)BIZ DB然后將消息發(fā)送出去.
設(shè)計(jì)目的
少做一次DB的存儲(chǔ),在高并發(fā)場(chǎng)景下,最關(guān)心的不是消息百分百投遞成功,而是一定要保證性能磺平,保證能抗得住這么大的并發(fā)量魂仍。所以能節(jié)省數(shù)據(jù)庫(kù)的操作就盡量節(jié)省,異步地進(jìn)行補(bǔ)償.
其實(shí)在主流程里面是沒(méi)有Callback service的拣挪,它屬于一個(gè)補(bǔ)償?shù)姆?wù)擦酌,整個(gè)核心鏈路就是生產(chǎn)端入庫(kù)業(yè)務(wù)消息,發(fā)送消息到MQ菠劝,消費(fèi)端監(jiān)聽(tīng)隊(duì)列赊舶,消費(fèi)消息。其他的步驟都是一個(gè)補(bǔ)償機(jī)制赶诊。
小結(jié)
這兩種方案都是可行的笼平,需要根據(jù)實(shí)際業(yè)務(wù)來(lái)進(jìn)行選擇,方案二也是互聯(lián)網(wǎng)大廠(chǎng)更為經(jīng)典和主流的解決方案.但是若對(duì)性能要求不是那么高,方案一要更簡(jiǎn)單.
3 冪等性
3.1 什么是冪等性
用戶(hù)對(duì)于同一操作發(fā)起的一次請(qǐng)求或者多次請(qǐng)求的結(jié)果是一致的
比如數(shù)據(jù)庫(kù)的樂(lè)觀(guān)鎖,在執(zhí)行更新操作前,先去數(shù)據(jù)庫(kù)查詢(xún)version,然后執(zhí)行更新語(yǔ)句,以version作為條件,如果執(zhí)行更新時(shí)有其他人先更新了這張表的數(shù)據(jù),那么這個(gè)條件就不生效了,也就不會(huì)執(zhí)行操作了,通過(guò)這種樂(lè)觀(guān)鎖的機(jī)制來(lái)保障冪等性.
3.2 Con - 冪等性
3.2.1 什么是Con - 冪等性
在業(yè)務(wù)高峰期最容易產(chǎn)生消息重復(fù)消費(fèi)問(wèn)題,當(dāng)Con消費(fèi)完消息時(shí),在給Pro返回ack時(shí)由于網(wǎng)絡(luò)中斷,導(dǎo)致Pro未收到確認(rèn)信息,該條消息就會(huì)重新發(fā)送并被Con消費(fèi),但實(shí)際上該消費(fèi)者已成功消費(fèi)了該條消息,這就造成了重復(fù)消費(fèi).
而Con - 冪等性,即消息不會(huì)被多次消費(fèi),即使我們收到了很多一樣的消息.
3.2.2 主流冪等性實(shí)現(xiàn)方案
3.2.2.1 唯一ID+指紋碼
核心:利用數(shù)據(jù)庫(kù)主鍵去重
- 唯一ID:業(yè)務(wù)表的主鍵
-
指紋碼:為了區(qū)別每次正常操作的碼,每次操作時(shí)生成指紋碼舔痪;可以用時(shí)間戳+業(yè)務(wù)編號(hào)或者標(biāo)志位(具體視業(yè)務(wù)場(chǎng)景而定)
- 優(yōu)勢(shì)
實(shí)現(xiàn)簡(jiǎn)單 - 弊端
高并發(fā)下有數(shù)據(jù)庫(kù)寫(xiě)入的性能瓶頸 - 解決方案
根據(jù)ID進(jìn)行分庫(kù)分表算法路由
小結(jié)
首先我們需要根據(jù)消息生成一個(gè)全局唯一ID寓调,然后還需要加上一個(gè)指紋碼。這個(gè)指紋碼它并不一定是系統(tǒng)去生成的锄码,而是一些外部的規(guī)則或者內(nèi)部的業(yè)務(wù)規(guī)則去拼接捶牢,它的目的就是為了保障這次操作是絕對(duì)唯一的。
將ID + 指紋碼拼接好的值作為數(shù)據(jù)庫(kù)主鍵巍耗,就可以進(jìn)行去重了秋麸。即在消費(fèi)消息前呢,先去數(shù)據(jù)庫(kù)查詢(xún)這條消息的指紋碼標(biāo)識(shí)是否存在炬太,沒(méi)有就執(zhí)行insert操作灸蟆,如果有就代表已經(jīng)被消費(fèi)了,就不需要管了
3.2.2.2 利用Redis原子性
這里我們使用Redis實(shí)現(xiàn)冪等,還需要考慮如下問(wèn)題
- 我們是否要進(jìn)行數(shù)據(jù)落庫(kù),如果落庫(kù),那么數(shù)據(jù)庫(kù)和緩存如何做到原子性?
如果你想用事務(wù),放棄吧,Redis緩存事務(wù)和MySQL事務(wù)根本不是同一個(gè)事務(wù) - 如果不落庫(kù),那么都存儲(chǔ)到緩存中,定時(shí)同步的策略如何設(shè)置為好?
這里只提用Redis的原子性去解決MQ冪等性重復(fù)消費(fèi)的問(wèn)題
MQ的冪等性問(wèn)題 根本在于的是生產(chǎn)端未正常接收ACK亲族,可能是網(wǎng)絡(luò)抖動(dòng)炒考、網(wǎng)絡(luò)中斷導(dǎo)致
可能的方案
Con在消費(fèi)開(kāi)始時(shí)將 ID放入到Redis的BitMap中,Pro每次生產(chǎn)數(shù)據(jù)時(shí)霎迫,從Redis的BitMap對(duì)應(yīng)位置若不能取出ID斋枢,則生產(chǎn)消息發(fā)送,否則不進(jìn)行消息發(fā)送知给。
但是有人可能會(huì)說(shuō)瓤帚,萬(wàn)一Con描姚,ProRedis命令執(zhí)行失敗了怎么辦,雖然又出現(xiàn)重復(fù)消費(fèi)又出現(xiàn)Redis非正常執(zhí)行命令的可能性極低戈次,但是萬(wàn)一呢轩勘?
OK,我們可以在Redis命令執(zhí)行失敗時(shí)怯邪,將消息落庫(kù)绊寻,每日用定時(shí)器,對(duì)這種極特殊的消息進(jìn)行處理悬秉。
4 Confirm機(jī)制
4.1 什么是Confirm機(jī)制
- 消息的確認(rèn)
Pro投遞消息后,如果Broker收到消息,則會(huì)給Pro一個(gè)應(yīng)答 - Pro接收應(yīng)答
用來(lái)確定這條消息是否正常地發(fā)送到Broker,該法也是消息可靠性投遞的核心保障!
4.2 Confirm機(jī)制流程圖
Pro發(fā)送消息到Broker,Broker接收到消息后,產(chǎn)生回送響應(yīng)
Pro中有一個(gè)Confirm Listener異步監(jiān)聽(tīng)響應(yīng)應(yīng)答
4.2 實(shí)現(xiàn)Confirm機(jī)制
- 在channel上開(kāi)啟確認(rèn)模式:channel.confirmSelect()
- 在channel上添加監(jiān)聽(tīng):addConfirmListener
監(jiān)聽(tīng)成功和失敗的返回結(jié)果澄步,根據(jù)具體的結(jié)果對(duì)消息進(jìn)行重新發(fā)送、或記錄日志等后續(xù)處理
接下來(lái)就讓我們根據(jù)原理進(jìn)行實(shí)操吧!
-
Con端
-
Pro端
-
啟動(dòng)Con,檢查管控臺(tái)
-
啟動(dòng)Pro
5 Return機(jī)制
5.1 什么是Return機(jī)制
- Return Listener 用于處理一些不可路由的消息
- Pro通過(guò)指定一個(gè)Exchange和Routingkey,把消息送到某一個(gè)隊(duì)列中,然后Con監(jiān)聽(tīng)隊(duì)列,進(jìn)行消費(fèi)
- 但如果我們?cè)诎l(fā)送消息時(shí),當(dāng)前Exchange不存在或者Routingkey路由不到,如果我們要監(jiān)聽(tīng)這種不可達(dá)的消息,就要用到Return Listener
5.2 Return機(jī)制示意圖
5.3 實(shí)現(xiàn)Return機(jī)制
- 添加return監(jiān)聽(tīng):addReturnListener和泌,生產(chǎn)端去監(jiān)聽(tīng)這些不可達(dá)的消息镐躲,做一些后續(xù)處理是趴,比如說(shuō)简僧,記錄下消息日志兰绣,或者及時(shí)去跟蹤記錄,有可能重新設(shè)置一下就好了
在基礎(chǔ)的API中的一個(gè)關(guān)鍵的配置項(xiàng):Mandatory
如果為true聋丝,則監(jiān)聽(tīng)器會(huì)接收到路由不可達(dá)的消息,然后進(jìn)行后續(xù)處理
如果為false,那么broker端自動(dòng)刪除該消息
-
Con
-
Pro
-
啟動(dòng)Con
-
啟動(dòng)Pro
由于Pro設(shè)置的是一個(gè)錯(cuò)誤的路由key索烹,所以消費(fèi)端沒(méi)有任何打印,而生產(chǎn)端打印了如下內(nèi)容
如果我們將 Mandatory 屬性設(shè)置為false弱睦,對(duì)于不可達(dá)的消息會(huì)被Broker直接刪除百姓,那么Pro就不會(huì)進(jìn)行任何打印了。如果我們的路由key設(shè)置為正確的况木,那么Con能夠正確消費(fèi)垒拢,Pro也不會(huì)進(jìn)行任何打印。
6 Con - 自定義監(jiān)聽(tīng)
- 之前我們都是在代碼中編寫(xiě)while循環(huán),通過(guò)
consumer.nextDelivery
方法獲取下一條消息,然后進(jìn)行消費(fèi)處理 - 其實(shí)我們還有另一種選擇,使用自定義的Consumer,它更方便,解耦性更強(qiáng),也是在實(shí)際工作中最常用的使用方式
自定義Con實(shí)現(xiàn)只需要繼承 DefaultConsumer 類(lèi)火惊,重寫(xiě) handleDelivery 方法即可!
6.1 代碼實(shí)現(xiàn)
-
自定義Con
-
Con
-
Pro
-
啟動(dòng)Con后,查看管控臺(tái)
-
啟動(dòng)Pro,Con接收消息
7 Con - 限流
7.1 什么是Con - 限流
7.1.1 消息過(guò)載場(chǎng)景
- 假設(shè)我們有這樣的場(chǎng)景
Rabbitmq服務(wù)器有上萬(wàn)條未處理的消息,我們隨便打開(kāi)一個(gè)Con - Client,會(huì)造成:巨量的消息瞬間全部推送過(guò)來(lái),然而我們單個(gè)客戶(hù)端無(wú)法同時(shí)處理這么多數(shù)據(jù)!此時(shí)很有可能導(dǎo)致服務(wù)器崩潰求类,嚴(yán)重的可能導(dǎo)致線(xiàn)上的故障。 - 還有一些其他的場(chǎng)景屹耐,比如說(shuō)單個(gè)Pro一分鐘產(chǎn)生了幾百條數(shù)據(jù),但是單個(gè)Con一分鐘可能只能處理60條,這個(gè)時(shí)候Pro-Con肯定是不平衡的尸疆。通常Pro是沒(méi)辦法做限制的。所以Con肯定需要做一些限流措施惶岭,否則如果超出最大負(fù)載寿弱,可能導(dǎo)致Con性能下降,服務(wù)器卡頓甚至崩潰等一系列嚴(yán)重后果
因此,我們需要限流
7.1.2 Con - 限流機(jī)制
RabbitMQ提供了一種qos (服務(wù)質(zhì)量保證)功能,即在非自動(dòng)確認(rèn)消息的前提下,如果一定數(shù)目的消息 (通過(guò)基于Con或者channel設(shè)置Qos的值) 未被確認(rèn)前,不消費(fèi)新的消息
不能設(shè)置自動(dòng)簽收功能(autoAck = false)
如果消息未被確認(rèn),就不會(huì)到達(dá)Con,目的就是給Pro減壓
限流設(shè)置API
void BasicQos(uint prefetchSize, ushort prefetchCount, bool global);
- prefetchSize: 單條消息的大小限制按灶,Con通常設(shè)置為0症革,表示不做限制
- prefetchCount: 一次最多能處理多少條消息
- global: 是否將上面設(shè)置true應(yīng)用于channel級(jí)別還是取false代表Con級(jí)別
prefetchSize和global這兩項(xiàng),RabbitMQ沒(méi)有實(shí)現(xiàn),暫且不研究
prefetchCount在autoAck=false
的情況下生效,即在自動(dòng)應(yīng)答的情況下該值無(wú)效
手工ACK
void basicAck(Integer deliveryTag,boolean multiple)
調(diào)用這個(gè)方法就會(huì)主動(dòng)回送給Broker一個(gè)應(yīng)答鸯旁,表示這條消息我處理完了噪矛,你可以給我下一條了量蕊。參數(shù)multiple表示是否批量簽收,由于我們是一次處理一條消息摩疑,所以設(shè)置為false
7.2 實(shí)現(xiàn)Con - 限流
-
自定義Con
-
Con
-
Pro
-
啟動(dòng)Con,查看管控臺(tái)
-
啟動(dòng)Pro,開(kāi)始發(fā)送消息,Con接收消息
-
實(shí)現(xiàn)限流,僅僅處理一條消息,其余的都在等待
-
現(xiàn)在,我們開(kāi)啟ACK應(yīng)答處理
- 重新啟動(dòng)Con,發(fā)現(xiàn)剩余的2條消息也全都發(fā)送并接收了!
-
我們之前是注釋掉手工ACK方法,然后啟動(dòng)消費(fèi)端和生產(chǎn)端畏铆,當(dāng)時(shí)Con只打印一條消息,這是因?yàn)槲覀冊(cè)O(shè)置了手工簽收,并且設(shè)置了一次只處理一條消息,當(dāng)我們沒(méi)有回送ACK應(yīng)答時(shí)雷袋,Broker端就認(rèn)為Con還沒(méi)有處理完這條消息,基于這種限流機(jī)制就不會(huì)給Con發(fā)送新的消息了,所以Con那時(shí)只打印了一條消息
8 Con - ACK & 重回隊(duì)列機(jī)制
8.1 ACK & NACK
當(dāng)我們?cè)O(shè)置autoACK=false
時(shí),就可以使用手工ACK方式了,其實(shí)手工方式包括了手工ACK與NACK
當(dāng)我們手工 ACK 時(shí),會(huì)發(fā)送給Broker一個(gè)應(yīng)答,代表消息處理成功,Broker就可回送響應(yīng)給Pro.
NACK 則表示消息處理失敗,如果設(shè)置了重回隊(duì)列,Broker端就會(huì)將沒(méi)有成功處理的消息重新發(fā)送.
使用方式
- Con消費(fèi)時(shí),如果由于業(yè)務(wù)異常,我們可以手工 NACK 記錄日志,然后進(jìn)行補(bǔ)償
API:void basicNack(long deliveryTag, boolean multiple, boolean requeue)
- 如果由于服務(wù)器宕機(jī)等嚴(yán)重問(wèn)題,我們就需要手工 ACK 保障Con消費(fèi)成功
API:void basicAck(long deliveryTag, boolean multiple)
8.2 重回隊(duì)列
- 重回隊(duì)列是為了對(duì)沒(méi)有處理成功的消息,將消息重新投遞給Broker
- 重回隊(duì)列,會(huì)把消費(fèi)失敗的消息重新添加到隊(duì)列的尾端,供Con繼續(xù)消費(fèi)
- 一般在實(shí)際應(yīng)用中,都會(huì)關(guān)閉重回隊(duì)列,即設(shè)置為false
8.3 實(shí)現(xiàn)機(jī)制
-
Con,關(guān)閉自動(dòng)簽收功能
-
自定義Con,對(duì)第一條消息(序號(hào)0)進(jìn)行NACK,并設(shè)置重回隊(duì)列
-
Pro 對(duì)消息設(shè)置序號(hào),以便區(qū)分
-
啟動(dòng)Con,查看管控臺(tái)
-
啟動(dòng)Pro,這里第一條消息由于我們調(diào)用了NACK辞居,并且設(shè)置了重回隊(duì)列楷怒,所以會(huì)導(dǎo)致該條消息一直重復(fù)發(fā)送,消費(fèi)端就會(huì)一直循環(huán)消費(fèi)
9 TTL機(jī)制
9.1 什么是TTL
- TTL(Time To Live),即生存時(shí)間
- RabbitMQ支持消息的過(guò)期時(shí)間瓦灶,在消息發(fā)送時(shí)可以進(jìn)行指定
- RabbitMQ支持為每個(gè)隊(duì)列設(shè)置消息的超時(shí)時(shí)間鸠删,從消息入隊(duì)列開(kāi)始計(jì)算,只要超過(guò)了隊(duì)列的超時(shí)時(shí)間配置贼陶,那么消息會(huì)被自動(dòng)清除
9.2 管控臺(tái)演示
-
新增一個(gè)Q
-
新增一個(gè)交換機(jī)
-
綁定
-
Q中也顯示了相關(guān)的綁定信息
-
發(fā)送消息
-
10s后,消息被清除為0
10 死信隊(duì)列機(jī)制
10.1 什么是死信隊(duì)列
DLX - 死信隊(duì)列(dead-letter-exchange)
利用DLX,當(dāng)消息在一個(gè)隊(duì)列中變成死信 (dead message) 之后,它能被重新publish到另一個(gè)Exchange中,這個(gè)Exchange就是DLX.
10.2 死信隊(duì)列的產(chǎn)生場(chǎng)景
- 消息被拒絕(basic.reject / basic.nack),并且requeue = false
- 消息因TTL過(guò)期
- 隊(duì)列達(dá)到最大長(zhǎng)度
10.3 死信的處理過(guò)程
- DLX亦為一個(gè)普通的Exchange,它能在任何隊(duì)列上被指定,實(shí)際上就是設(shè)置某個(gè)隊(duì)列的屬性
- 當(dāng)某隊(duì)列中有死信時(shí),RabbitMQ會(huì)自動(dòng)地將該消息重新發(fā)布到設(shè)置的Exchange,進(jìn)而被路由到另一個(gè)隊(duì)列
- 可以監(jiān)聽(tīng)這個(gè)隊(duì)列中的消息做相應(yīng)的處理.該特性可以彌補(bǔ)RabbitMQ 3.0以前支持的
immediate
參數(shù)的功能
10.4 死信隊(duì)列的配置
-
設(shè)置死信隊(duì)列的exchange和queue,然后進(jìn)行綁定
- Exchange:dlx.exchange
- Queue: dlx.queue
- RoutingKey:#
正常聲明交換機(jī)刃泡、隊(duì)列、綁定碉怔,只不過(guò)我們需要在隊(duì)列加上一個(gè)參數(shù)即可
arguments.put(" x-dead-letter-exchange"烘贴,"dlx.exchange");
這樣消息在過(guò)期、requeue撮胧、 隊(duì)列在達(dá)到最大長(zhǎng)度時(shí)桨踪,消息就可以直接路由到死信隊(duì)列!
10.5 實(shí)操演示
-
自定義Con
-
Pro
-
Con
-
啟動(dòng)Con,查看管控臺(tái)
-
現(xiàn)在,讓我們停止Con,并啟動(dòng)Pro,由于沒(méi)有Con,TTL為10s的消息將送往死信隊(duì)列
-
10s后
- 實(shí)際環(huán)境我們還需要對(duì)死信隊(duì)列進(jìn)行一個(gè)監(jiān)聽(tīng)和處理芹啥,當(dāng)然具體的處理邏輯和業(yè)務(wù)相關(guān)锻离,這里只是簡(jiǎn)單演示死信隊(duì)列是否生效。
11 總結(jié)
本文專(zhuān)注RabbitMQ高級(jí)特性的學(xué)習(xí)
首先介紹了大廠(chǎng)在實(shí)際使用中是如何保障消息投遞成功和冪等性的墓怀,以及對(duì)RabbitMQ的確認(rèn)消息汽纠、返回消息、ACK與重回隊(duì)列傀履、消息的限流疏虫,以及對(duì)超時(shí)時(shí)間、死信隊(duì)列的使用
最后,感謝您的閱讀!
參考
RabbitMQ 100% 投遞成功方案詳解
RabbitMQ 從入門(mén)到精通(二)
RabbitMQ 冪等性概念及業(yè)界主流解決方案
RabbitMQ從入門(mén)到精通(三)