1. 死信隊(duì)列&死信交換器:
DLX 全稱(Dead-Letter-Exchange),稱之為死信交換器,當(dāng)消息變成一個(gè)死信之后,如果這個(gè)消息所在的隊(duì)列存在x-dead-letter-exchange參數(shù)蹬敲,那么它會(huì)被發(fā)送到x-dead-letter-exchange對(duì)應(yīng)值的交換器上读整,這個(gè)交換器就稱之為死信交換器宾舅,與這個(gè)死信交換器綁定的隊(duì)列就是死信隊(duì)列在验。
說(shuō)實(shí)在的,死信隊(duì)列和普通隊(duì)列沒(méi)啥區(qū)別绩社,都需要自己創(chuàng)建Queue摔蓝、Exchange,然后通過(guò)RoutingKey綁定到Exchange上愉耙。只不過(guò)死信隊(duì)列的RoutingKey和Exchange要作為參數(shù)贮尉,綁定到正常的隊(duì)列上。
2. 死信消息:
- (1)消息被拒絕(Basic.Reject或Basic.Nack)并且設(shè)置 requeue 參數(shù)的值為 false
- (2)消息過(guò)期了
- (3)隊(duì)列達(dá)到最大的長(zhǎng)度
3. 過(guò)期消息:
在 rabbitmq 中存在2種方法可設(shè)置消息的過(guò)期時(shí)間:
- 第一種通過(guò)對(duì)隊(duì)列進(jìn)行設(shè)置朴沿,這種設(shè)置后猜谚,該隊(duì)列中所有的消息都存在相同的過(guò)期時(shí)間;
- 第二種通過(guò)對(duì)消息本身進(jìn)行設(shè)置,那么每條消息的過(guò)期時(shí)間都不一樣悯仙。
如果同時(shí)使用這2種方法龄毡,那么以過(guò)期時(shí)間小的那個(gè)數(shù)值為準(zhǔn)。當(dāng)消息達(dá)到過(guò)期時(shí)間還沒(méi)有被消費(fèi)锡垄,那么那個(gè)消息就成為了一個(gè) 死信 消息沦零。
- (1)隊(duì)列設(shè)置:在隊(duì)列申明的時(shí)候使用** x-message-ttl **參數(shù),單位為 毫秒货岭;
- 隊(duì)列中這個(gè)屬性的設(shè)置要在第一次聲明隊(duì)列的時(shí)候設(shè)置才有效路操,如果隊(duì)列一開始已存在且沒(méi)有這個(gè)屬性疾渴,則要?jiǎng)h掉隊(duì)列再重新聲明才可以。
- 隊(duì)列的 ttl 只能被設(shè)置為某個(gè)固定的值屯仗,一旦設(shè)置后則不能更改搞坝,否則會(huì)拋出異常。
- (2)單個(gè)消息設(shè)置:是設(shè)置消息屬性的 expiration 參數(shù)的值魁袜,單位為 毫秒桩撮。
說(shuō)明:
對(duì)于第一種設(shè)置隊(duì)列屬性的方法,一旦消息過(guò)期峰弹,就會(huì)從隊(duì)列中抹去店量;而在第二種方法中,即使消息過(guò)期鞠呈,也不會(huì)馬上從隊(duì)列中抹去融师,因?yàn)槊織l消息是否過(guò)期是在即將投遞到消費(fèi)者之前判定的。
為什么這兩種方法處理的方式不一樣?
因?yàn)榈谝环N方法里蚁吝,隊(duì)列中己過(guò)期的消息肯定在隊(duì)列頭部旱爆,RabbitMQ只要定期從隊(duì)頭開始掃描是否有過(guò)期的消息即可。而第二種方法里窘茁,每條消息的過(guò)期時(shí)間不同怀伦,如果要?jiǎng)h除所有過(guò)期消息勢(shì)必要掃描整個(gè)隊(duì)列,所以不如等到此消息即將被消費(fèi)時(shí)再判定是否過(guò)期,如果過(guò)期再進(jìn)行刪除即可庙曙。這樣只判斷隊(duì)列頭是否過(guò)期的方法的優(yōu)勢(shì)是空镜,不用時(shí)刻掃描整個(gè)隊(duì)列的所有消息去判斷哪個(gè)過(guò)期,這樣會(huì)非常耗資源捌朴。
另外,還需要注意的一點(diǎn)是张抄,如果不設(shè)置TTL砂蔽,表示消息永遠(yuǎn)不會(huì)過(guò)期,如果將TTL設(shè)置為0署惯,則表示除非此時(shí)可以直接投遞該消息到消費(fèi)者左驾,否則該消息將會(huì)被丟棄。
4. 延時(shí)隊(duì)列
延時(shí)隊(duì)列极谊,顧名思義诡右,不是及時(shí)的隊(duì)列,也就是發(fā)送者發(fā)出的消息要延遲一段時(shí)間轻猖,消費(fèi)者才能接受到帆吻。有一個(gè)很典型的應(yīng)用場(chǎng)景就是訂單30分鐘內(nèi)未支付就關(guān)閉訂單,還有一種場(chǎng)景咙边,賬單24小時(shí)未確認(rèn)猜煮,就發(fā)送提醒消息次员。
在rabbitmq中是不存在延時(shí)隊(duì)列,如果需要使用的話王带,就需要安裝延時(shí)隊(duì)列插件淑蔚。另外,我們也可以通過(guò)過(guò)期隊(duì)列消息和死信隊(duì)列來(lái)模擬出延時(shí)隊(duì)列愕撰。消費(fèi)者監(jiān)聽死信交換器綁定的隊(duì)列刹衫,而不要監(jiān)聽消息發(fā)送的隊(duì)列,就可以模擬出延時(shí)隊(duì)列了搞挣。
使用延時(shí)隊(duì)列插件绪妹,可以參考文章(https://www.cnblogs.com/geekdc/p/13550620.html),使用過(guò)期隊(duì)列消息和死信隊(duì)列模擬延時(shí)隊(duì)列柿究,實(shí)現(xiàn)流程如下圖邮旷,具體代碼實(shí)現(xiàn)可自行搜索,這個(gè)資料也比較多蝇摸。
通過(guò)過(guò)期消息和死信隊(duì)列來(lái)模擬出延時(shí)隊(duì)列:
前面講了過(guò)期消息有兩種實(shí)現(xiàn)方法婶肩,第一種是通過(guò)對(duì)隊(duì)列進(jìn)行設(shè)置,第二種是通過(guò)對(duì)消息本身進(jìn)行設(shè)置貌夕。
第一種方法通過(guò)隊(duì)列設(shè)置律歼,需要在隊(duì)列聲明的時(shí)候設(shè)置才有效。而如果使用這種方法啡专,那么每增加一個(gè)新的時(shí)間需求险毁,就要增加一個(gè)隊(duì)列,顯然這種方法不夠靈活们童。
既然第一種方法不夠靈活畔况,那么咱通過(guò)第二種方法就可以實(shí)現(xiàn)靈活性。然而事情并沒(méi)有那么簡(jiǎn)單慧库,因?yàn)榍懊嬉呀?jīng)講了跷跪,如果使用在消息屬性上設(shè)置TTL的方式,消息可能并不會(huì)按時(shí)“死亡“齐板,因?yàn)镽abbitMQ只會(huì)檢查隊(duì)列頭部的消息是否過(guò)期吵瞻,如果過(guò)期則丟到死信隊(duì)列,所以如果隊(duì)列中第一個(gè)消息的延時(shí)時(shí)長(zhǎng)很長(zhǎng)甘磨,而第二個(gè)消息的延時(shí)時(shí)長(zhǎng)很短橡羞,則第二個(gè)消息并不會(huì)優(yōu)先得到執(zhí)行。
所以總結(jié)一下济舆,可以看得出來(lái)卿泽,通過(guò)過(guò)期消息和死信隊(duì)列雖然可以模擬延時(shí)隊(duì)列,并無(wú)法達(dá)到一個(gè)靈活通用的延遲隊(duì)列吗冤。
參考文章:
1 https://www.cnblogs.com/mfrank/p/11260355.html
2 https://www.cnblogs.com/geekdc/p/13550620.html