RabbitMQ 死信隊(duì)列基礎(chǔ)概念與配置概述
1. 前言
Hello,大家好。本小節(jié)會(huì)為同學(xué)們介紹 RabbitMQ 中的死信隊(duì)列及其基礎(chǔ)配置。死信隊(duì)列作為 RabbitMQ 中最后一個(gè)特性,其在實(shí)際工作中發(fā)揮著重要的作用。本節(jié)會(huì)從死信隊(duì)列的前置概念開(kāi)始,到死信隊(duì)列的基礎(chǔ)概念,最后介紹死信隊(duì)列的基本使用方法和基本配置結(jié)束,詳細(xì)介紹死信隊(duì)列的基礎(chǔ)概念和基本使用方法。
話不多說(shuō),讓我們直入正題吧。
本節(jié)主要內(nèi)容:
-
死信隊(duì)列前置概念概述;
-
死信隊(duì)列基礎(chǔ)概念概述;
-
死信隊(duì)列基本使用概述;
2. 死信隊(duì)列前置概念概述
在正式介紹死信隊(duì)列的基礎(chǔ)概念之前,需要同學(xué)們先了解一些死信隊(duì)列的前置概念,這些前置概念是后續(xù)理解死信隊(duì)列的基礎(chǔ),同學(xué)們只有對(duì)這些前置概念有一個(gè)理解之后,才能很好地理解什么是死信隊(duì)列。
什么是隊(duì)列:
隊(duì)列并不是只存在于 RabbitMQ 中,隊(duì)列是一種計(jì)算機(jī)領(lǐng)域中的基本數(shù)據(jù)結(jié)構(gòu),其描述了數(shù)據(jù)在計(jì)算機(jī)內(nèi)存中垂直分布的特點(diǎn)。 我們可以把隊(duì)列看做是我們?nèi)粘I钪信抨?duì)做核酸的場(chǎng)景:當(dāng)有一個(gè)人去做的時(shí)候,這個(gè)時(shí)候沒(méi)有隊(duì)伍,直接做就行了;當(dāng)有十個(gè)人去做的時(shí)候,這個(gè)時(shí)候就需要排隊(duì)了,而排隊(duì)的這個(gè)過(guò)程就是隊(duì)列形成的過(guò)程。
當(dāng)再有人需要去做的時(shí)候,這個(gè)人只能排在隊(duì)尾,不能夠插隊(duì),而隊(duì)前的人由于比隊(duì)尾的人先到,所以隊(duì)前的人就比隊(duì)尾的人先做核酸,以此反復(fù)這個(gè)過(guò)程,直到所有人都做完核酸為止。
而隊(duì)列描述的就是這樣的場(chǎng)景,在上述例子中,形成隊(duì)伍的過(guò)程就是我們的應(yīng)用數(shù)據(jù)入隊(duì)的過(guò)程,先入隊(duì)的數(shù)據(jù)可以先被處理,而后入隊(duì)的數(shù)據(jù)只能等待前入隊(duì)的數(shù)據(jù)處理完畢之后才能進(jìn)行處理,這就是隊(duì)列先入先出的特點(diǎn)。
假設(shè)我們有 6 條數(shù)據(jù)需要入隊(duì),以下是數(shù)據(jù)入隊(duì)過(guò)程:

1 號(hào)數(shù)據(jù)會(huì)先入隊(duì),然后排在 1 好數(shù)據(jù)后面的 2 3 4 5 6 好數(shù)據(jù)會(huì)依次入隊(duì),入隊(duì)完成后的隊(duì)列如下圖所示:

說(shuō)白了,隊(duì)列就是數(shù)據(jù)按照固定的排列方式在計(jì)算機(jī)中存儲(chǔ)的一種表現(xiàn)形式,而隊(duì)列中的數(shù)據(jù)處理原則就是先入隊(duì)的數(shù)據(jù)先進(jìn)行處理,后入隊(duì)的數(shù)據(jù)后進(jìn)行處理。RabbitMQ 中的隊(duì)列也是一樣的,只不過(guò)這些隊(duì)列里面存儲(chǔ)的都是被稱(chēng)為消息的數(shù)據(jù),所以這些隊(duì)列被稱(chēng)為消息隊(duì)列, 即在 RabbitMQ 中,根據(jù)消息類(lèi)型的不同,會(huì)形成很多不同類(lèi)型的隊(duì)列,但是這些隊(duì)列歸根到底,其本質(zhì)依然是消息隊(duì)列。
什么是死信:
我們知道,在 RabbitMQ 中充當(dāng)主角的就是消息,在不同場(chǎng)景下,消息會(huì)有不同地表現(xiàn)。死信就是消息在特定場(chǎng)景下的一種表現(xiàn)形式,這些場(chǎng)景包括:消息被拒絕訪問(wèn),即 RabbitMQ Server 返回 nack 的信號(hào)時(shí)、消息的 TTL 過(guò)期時(shí)、消息隊(duì)列達(dá)到最大長(zhǎng)度,消息不能入隊(duì)時(shí)。
經(jīng)常產(chǎn)生死信的場(chǎng)景就是上述三種場(chǎng)景,即消息在這三種場(chǎng)景中時(shí),被稱(chēng)為死信。
3. 死信隊(duì)列基礎(chǔ)概念概述
通過(guò)前置概念的介紹,我們知道了死信的基礎(chǔ)的概念,那么死信隊(duì)列又是什么呢?
結(jié)合上述對(duì)隊(duì)列基礎(chǔ)概念的介紹,我們不難得出:死信隊(duì)列就是用于儲(chǔ)存死信的消息隊(duì)列,在死信隊(duì)列中,有且只有死信構(gòu)成,不會(huì)存在其余類(lèi)型的消息,這就是死信隊(duì)列。
死信隊(duì)列在 RabbitMQ 中并不會(huì)單獨(dú)存在,往往死信隊(duì)列都會(huì)綁定這一個(gè)普通的消息隊(duì)列,當(dāng)所綁定的消息隊(duì)列中,有消息變成死信了,那么這個(gè)消息就會(huì)重新被交換機(jī)路由到指定的死信隊(duì)列中去,我們可以通過(guò)對(duì)這個(gè)死信隊(duì)列進(jìn)行監(jiān)聽(tīng),從而手動(dòng)的去對(duì)這一消息進(jìn)行補(bǔ)償。
那么,我們到底如何來(lái)使用死信隊(duì)列呢?
4. 死信隊(duì)列基本使用概述
在 RabbitMQ 中,死信隊(duì)列的標(biāo)識(shí)為 x-dead-letter-exchange ,通過(guò)觀察死信隊(duì)列的標(biāo)識(shí),我們不難發(fā)現(xiàn),其標(biāo)識(shí)最后為 exchange ,即 RabbitMQ 中的交換機(jī),沒(méi)錯(cuò),RabbitMQ 中的死信隊(duì)列就是由死信交換機(jī)而得出的。
要想使用死信隊(duì)列,我們需要首先聲明一個(gè)普通的消息隊(duì)列,并將死信隊(duì)列的標(biāo)識(shí)綁定到這個(gè)普通的消息隊(duì)列上, 這個(gè)過(guò)程需要我們?cè)谏a(chǎn)端進(jìn)行配置,代碼如下所示:
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("xx");
connectionFactory.setPort("5672");
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChanel();
Map<String, Object> argumentsMap = new HashMap();
argumentsMap.put("x-dead-letter-exchange", "dlx_exchange");
channel.exchangeDeclare("dlx_common_exchange", "direct", true, false, null);
channel.queueDeclare("dlx_common_queue", true, false, false, argumentsMap);
channel.queueBind("dlx_common_queue", "dlx_common_exchange", routingKey);
代碼解釋?zhuān)?/strong>
第 1-5 行,我們使用 ConnectionFactory 創(chuàng)建了一個(gè)客戶(hù)端連接 RabbitMQ Server 的連接。
第 6 行,我們使用建立好的連接,來(lái)創(chuàng)建了一個(gè)頻道 channel 。
第 7-8 行,我們聲明了一個(gè)普通隊(duì)列的額外參數(shù)的 Map ,這個(gè) Map 的 key 就是死信隊(duì)列的標(biāo)識(shí),value 就是我們后續(xù)聲明的真正的死信交換機(jī)的名稱(chēng)。
第 9-10 行,我們依次使用 channel 的 exchangeDeclare 方法和 queueDeclare 方法,分別聲明了一個(gè)名為 dlx_common_exchange 的交換機(jī)和名為 dlx_common_queue 的普通消息隊(duì)列,之所以名稱(chēng)中有 common ,是因?yàn)橐獙?duì)這個(gè)交換機(jī)和隊(duì)列做一個(gè)標(biāo)識(shí),表示該交換機(jī)和隊(duì)列是綁定了死信隊(duì)列的。
第 11 行,我們使用 channel 的 queueBind 方法來(lái)講聲明的普通交換機(jī)和消息隊(duì)列進(jìn)行綁定,并且制定了 routingKey ,這樣消息就可以經(jīng) dlx_common_exchange 根據(jù) routingKey 來(lái)路由到 dlx_common_queue 中。
在我們聲明了要綁定死信隊(duì)列的普通隊(duì)列之后,最后我們需要聲明真正的死信隊(duì)列,代碼如下所示:
// 省略客戶(hù)端連接 RabbitMQ Server 的過(guò)程
channel.exchangeDeclare("dlx_exchange", "direct", true, false, null);
channel.queueDeclare("dlx_queue", true, false, false, null);
channel.queueBind("dlx_queue", "dlx_exchange", routingKey);
代碼解釋?zhuān)?/strong>
第 1 行,我們使用 chanel 的 exchangeDeclare 方法來(lái)聲明了一個(gè)名為 dlx_exchange 的交換機(jī)。
第 2 行,我們使用 channel 的 queueDeclare 方法來(lái)聲明了一個(gè)名為 dlx_queue 的隊(duì)列。
第 3 行,我們使用 channel 的 queueBind 方法,來(lái)將 dlx_exchange 的交換機(jī)與 dlx_queue 隊(duì)列進(jìn)行了綁定。
當(dāng)我們完成上述過(guò)程之后,死信隊(duì)列就配置完成了,這也是死信隊(duì)列的基本使用方法。
Tips: 1. 從聲明死信隊(duì)列的代碼段中,我們不難看出,我們所聲明的交換機(jī)和隊(duì)列也都是普通的,只不過(guò)我們聲明的這個(gè)交換機(jī)和隊(duì)列是用來(lái)存儲(chǔ) dlx_common_queue 隊(duì)列中的死信的;
2. 死信隊(duì)列的使用在實(shí)際工作中非常重要,它可以幫助我們對(duì)那些異常的消息進(jìn)行監(jiān)控,并根據(jù)這些監(jiān)控信息制定相應(yīng)的消息補(bǔ)償策略,這點(diǎn)同學(xué)們注意;
3. 一定要注意在聲明普通隊(duì)列時(shí),我們聲明的名為 argumetsMap 的變量,這個(gè)是綁定死信隊(duì)列的關(guān)鍵。
5. 小結(jié)

本小節(jié)為同學(xué)們介紹了 RabbitMQ 中,死信隊(duì)列的前置概念、死信隊(duì)列的基礎(chǔ)概念,以及死信隊(duì)列的基本使用。我們只有在了解了死信隊(duì)列的前置概念之后,我們才能理解死信隊(duì)列的基礎(chǔ)概念,同時(shí),我們只有清楚的明白了應(yīng)用死信隊(duì)列的步驟,我們才能正確的用好死信隊(duì)列。
死信隊(duì)列在實(shí)際工作中使用頻率非常高,希望同學(xué)們可以清楚地理解本節(jié)中的基礎(chǔ)概念和代碼實(shí)現(xiàn),這些都是應(yīng)用死信隊(duì)列基礎(chǔ)中的基礎(chǔ),望同學(xué)們注意。