RabbitMQ 核心基礎(chǔ)概念詳解
1. 前言
Hello,大家好。本節(jié)會(huì)為同學(xué)們介紹 RabbitMQ 中的核心基礎(chǔ)概念。這些核心基礎(chǔ)概念組成 RabbitMQ 的基本元素,貫穿整個(gè) RabbitMQ 的始終,如果我們不了解這些基礎(chǔ)概念,那么當(dāng)我們?cè)谑褂?RabbitMQ 時(shí),就會(huì)一臉懵,所以,在使用 RabbitMQ 之前,充分了解 RabbitMQ 的這些基礎(chǔ)概念是非常有必要的。
本節(jié)主要內(nèi)容:
-
AMQP 協(xié)議與 RabbitMQ 的聯(lián)系;
-
RabbitMQ 基礎(chǔ)概念梳理;
-
RabbitMQ 基礎(chǔ)概念詳解。
希望各位同學(xué)可以完全理解本節(jié)內(nèi)容,這對(duì)學(xué)習(xí) RabbitMQ 有著至關(guān)重要的作用。
2. AMQP 協(xié)議與 RabbitMQ 的聯(lián)系
2.1 什么是 AMQP 協(xié)議
說(shuō)起 AMQP 協(xié)議,我們可能會(huì)感到有點(diǎn)陌生,那么為什么還要了解 AMQP 協(xié)議呢? 因?yàn)榱私馐裁词?AMQP 協(xié)議可以為我們學(xué)習(xí) RabbitMQ 打下知識(shí)基礎(chǔ),讓我們很清楚的知道 RabbitMQ 是用來(lái)做什么的。
AMQP 協(xié)議,即 Advanced Message Queuing Protocol,直譯為高級(jí)消息隊(duì)列協(xié)議,我們只要知道 AMQP 協(xié)議就是一個(gè)高級(jí)消息隊(duì)列協(xié)議就行了。
2.2 與 RabbitMQ 的聯(lián)系
AMQP 協(xié)議由三大模塊組成,分別是交換機(jī)、消息隊(duì)列、消息隊(duì)列路由。通過(guò)這三大模塊間的配合,可以實(shí)現(xiàn)對(duì)消息的發(fā)送、消息的監(jiān)聽(tīng)等功能。
RabbitMQ 就是借鑒了 AMQP 協(xié)議的組成模塊,在 AMQP 協(xié)議的基礎(chǔ)上,對(duì)這些模塊進(jìn)行整合、拓展,并最終形成了基于 erlang 語(yǔ)言和 AMQP 協(xié)議的一個(gè)完備的消息中間件,因此,在 RabbitMQ 中,有些基礎(chǔ)概念是和 AMQP 協(xié)議中的是幾乎一樣的,而有些概念確是 AMQP 協(xié)議中沒(méi)有的。
而無(wú)論 AMQP 協(xié)議中有沒(méi)有其他的概念,在這里會(huì)一并介紹。
3. RabbitMQ 基礎(chǔ)概念梳理
在詳細(xì)開(kāi)始介紹 RabbitMQ 的基礎(chǔ)概念之前,讓我們先來(lái)看一下,在 RabbitMQ 中都有哪些基礎(chǔ)概念需要我們知道。
序號(hào) | 名稱(chēng) |
---|---|
01 | 消息 |
02 | 虛擬主機(jī) |
03 | 交換機(jī) |
04 | 路由 Key |
05 | 頻道 |
06 | 消息隊(duì)列 |
07 | 生產(chǎn)者 |
08 | 消費(fèi)者 |
Tips: 上述清單中的生產(chǎn)者與消費(fèi)者概念,并不是 RabbitMQ 中特有的概念,考慮到學(xué)習(xí)本課程的同學(xué)基礎(chǔ),在這里就一并進(jìn)行介紹了。
4. RabbitMQ 基礎(chǔ)概念詳解
4.1 生產(chǎn)者與消費(fèi)者
定義:
在了解什么是生產(chǎn)者與消費(fèi)者時(shí),我們可以先不從計(jì)算機(jī)專(zhuān)業(yè)的角度考慮什么是生產(chǎn)者與消費(fèi)者,我們可以先來(lái)了解它們的字面意思。從生活角度考慮,生產(chǎn)者就是生產(chǎn)某某東西的人,而消費(fèi)者就是消費(fèi)某某東西的人,它們兩個(gè)一個(gè)是生產(chǎn),一個(gè)是消費(fèi),且保持著一種先生產(chǎn)后消費(fèi)的關(guān)系。
針對(duì)于計(jì)算機(jī)專(zhuān)業(yè)角度來(lái)說(shuō),生產(chǎn)者就是生產(chǎn)一條數(shù)據(jù)的手段或者途徑,而消費(fèi)者則是消費(fèi)一條數(shù)據(jù)的手段或者途徑。在 RabbitMQ 中,生產(chǎn)者指的就是具備生產(chǎn)一條消息能力的方法,消費(fèi)者指的就是具備消費(fèi)一條消息能力的方法。
代碼實(shí)現(xiàn):
那么我們?nèi)绾卧?RabbitMQ 中來(lái)定義一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者呢?接下來(lái)就讓我們來(lái)看一下 RabbitMQ 中生產(chǎn)者與消費(fèi)者的基礎(chǔ)通用 API :
在 RabbitMQ 中要想聲明一個(gè)生產(chǎn)者,我們首先需要與 RabbitMQ Server 建立通信,即將我們的應(yīng)用程序與 RabbitMQ 的服務(wù)器建立鏈接,如下代碼所示:
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort("5672");
Connection connection = connectionFactory.newConnection();
代碼解釋?zhuān)?/strong>
第 1 行,我們實(shí)例化了一個(gè) RabbitMQ 的鏈接工廠,這是與 RabbitMQ 服務(wù)器建立鏈接的必要基礎(chǔ)操作。
第 2-3 行,我們使用我們實(shí)例化的鏈接工廠中的 setHost 和 setPort 方法來(lái)設(shè)置我們需要鏈接的 RabbitMQ 服務(wù)器的 ip 地址,以及端口號(hào),RabbitMQ 服務(wù)默認(rèn)的端口號(hào)為 5672。
第 4 行,在將 RabbitMQ 服務(wù)的 host 和 port 設(shè)置完畢后,我們使用 connectionFactory 的 newConnection 方法來(lái)創(chuàng)建出了一條鏈接,并返回我們連接 RabbitMQ 服務(wù)的 connection 信息。
在建立好連接之后,我們就可以向 RabbitMQ 中發(fā)送消息了,如下代碼所示:
Channel channel = connection.createChannel();
String msg = "Hello RabbitMQ";
channel.basicPublish("", "test01", null, msg.getBytes());
現(xiàn)階段,在上段代碼中,我們只需要了解最后一行代碼所表示的含義即可。
代碼解釋?zhuān)?/strong>
第 3 行,我們使用了 channel 的 basicPublish 方法來(lái)將我們定義的 msg 消息投遞到 RabbitMQ 中,其中, basicPublish 方法的第一個(gè)參數(shù)表示交換機(jī)的名稱(chēng),第二個(gè)參數(shù)表示路由 Key 的名稱(chēng),第三個(gè)參數(shù)表示消息所設(shè)置的參數(shù),第四個(gè)參數(shù)表示將我們的 msg 數(shù)據(jù)轉(zhuǎn)換為 bytes 之后再進(jìn)行投遞。
通過(guò)上述代碼,我們就實(shí)現(xiàn)了 RabbitMQ 的生產(chǎn)端,那消費(fèi)端又該如何實(shí)現(xiàn)呢?
代碼實(shí)現(xiàn):
String queueName = "test01";
channel.queueDeclare(queueName, true, false, false, null);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel);
channel.basicConsume(queueName, true, defaultConsumer);
代碼解釋?zhuān)?/strong>
第 1 行,我們根據(jù)生產(chǎn)者聲明的路由 Key ,定義了一個(gè)名為 queueName 的變量,來(lái)接收路由 Key 。
第 2 行,我們使用 channel 的 queueDeclare 方法,來(lái)聲明一個(gè)名為 queueName 的隊(duì)列。
第 3 行,我們對(duì) RabbitMQ 中用來(lái)接收消息的 Consumer 進(jìn)行初始化。
第 4 行,我們使用 channel 的 basicConsume 方法,來(lái)講我們投遞到 RabbitMQ 中的消息進(jìn)行消費(fèi)。
Tips 在這里,我們只是對(duì) RabbitMQ 中如何實(shí)現(xiàn)生產(chǎn)端與消費(fèi)端進(jìn)行一個(gè)簡(jiǎn)單的了解,后續(xù)會(huì)進(jìn)行深入介紹。
4.2 消息
定義:
消息,顧名思義,就是我們平常所說(shuō)的一條信息、一條數(shù)據(jù),消息是 RabbitMQ 中的核心元素,我們產(chǎn)生的任何數(shù)據(jù),在 RabbitMQ 中都被稱(chēng)為消息。
在整個(gè) RabbitMQ 工作流程中間,有且只有消息被流轉(zhuǎn),我們使用 RabbitMQ 的目的就是來(lái)處理我們應(yīng)用程序中需要 RabbitMQ 來(lái)處理的任何消息,該消息可以是一句話(huà),可以是一張圖片,可以是一條視頻,也可以是一種文檔。
4.3 虛擬主機(jī)
定義:
虛擬主機(jī),即 Virtual Host ,是用來(lái)存儲(chǔ) RabbitMQ 中所有消息數(shù)據(jù)的集合,每個(gè) RabbitMQ 服務(wù)中默認(rèn)只有一臺(tái)虛擬主機(jī),并且提供用戶(hù)自定義虛擬主機(jī)的功能。
我們可以這樣理解:RabbitMQ 中的每個(gè)虛擬主機(jī)都是一臺(tái)數(shù)據(jù)庫(kù),在這個(gè)數(shù)據(jù)庫(kù)中會(huì)存儲(chǔ) RabbitMQ 的交換機(jī)、頻道、路由 Key ,以及消息隊(duì)列,每一個(gè)虛擬主機(jī)是一個(gè)獨(dú)立的單元,各虛擬主機(jī)之間不會(huì)相互干擾,各自完成各自的任務(wù)。
代碼實(shí)現(xiàn):
在 RabbitMQ 中,默認(rèn)的虛擬主機(jī)為 “/” ,即如果我們不指定我們的虛擬主機(jī),則所有的消息都會(huì)存儲(chǔ)到名稱(chēng)為 “/” 的虛擬主機(jī)下,而我們?nèi)绾问褂锰摂M主機(jī)呢?如下代碼所示:
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setVirtualHost("/");
代碼解釋?zhuān)?/strong>
第 2 行,我們使用 RabbitMQ 鏈接工廠的 setVirtualHost 方法,來(lái)為我們的鏈接指定一個(gè)虛擬主機(jī),而指定的虛擬主機(jī)就是 RabbitMQ 所提供的默認(rèn)虛擬主機(jī)。
Tips:
1. 一般來(lái)說(shuō),每一個(gè)應(yīng)用程序或者每一個(gè)獨(dú)立的業(yè)務(wù)模塊,都會(huì)創(chuàng)建屬于自己領(lǐng)域的虛擬主機(jī),目的就是為了和其他業(yè)務(wù)模塊分離開(kāi),同時(shí),這樣的架構(gòu)模式更利于不同業(yè)務(wù)數(shù)據(jù)的統(tǒng)計(jì)與維護(hù),在線(xiàn)上環(huán)境中,也更利于我們同學(xué)排查業(yè)務(wù)故障。
2. 如果你不知道你的應(yīng)用程序該如何劃分虛擬主機(jī),那就請(qǐng)使用 RabbitMQ 自帶的默認(rèn)虛擬主機(jī),這一點(diǎn)是很重要的。
4.4 交換機(jī)
定義:
交換機(jī),即 exchange ,是傳遞消息的中間工具,我們可以把交換機(jī)理解為,傳遞消息的媒介,即我們發(fā)到 RabbitMQ 服務(wù)器中的消息,在經(jīng)過(guò)虛擬主機(jī)之后,會(huì)首先到達(dá) exchange 中,然后由 exchange 根據(jù)不同的匹配策略來(lái)將消息傳遞到對(duì)應(yīng)的頻道中去。
針對(duì)不同的業(yè)務(wù)場(chǎng)景,RabbitMQ 為我們內(nèi)置了多種交換機(jī)供我們選擇,這里只是對(duì)交換機(jī)的概念做一個(gè)簡(jiǎn)單的介紹,后續(xù)我們?cè)僭敿?xì)介紹 RabbitMQ 中所有的交換機(jī)。
代碼實(shí)現(xiàn):
我們應(yīng)該如何選擇一種交換機(jī)呢?如下代碼所示:
channel.exchangeDeclare("test_exchange", "direct");
代碼解釋?zhuān)?/strong>
第 1 行,我們使用了 channel 的 exchangeDeclare 方法,來(lái)選擇了一種類(lèi)型的交換機(jī),該交換機(jī)類(lèi)型為直接交換機(jī),方法的第一個(gè)參數(shù)表示交換機(jī)的名稱(chēng),我們可以根據(jù)實(shí)際情況自定義交換機(jī)名稱(chēng),方法的第二個(gè)參數(shù)為交換機(jī)的類(lèi)型,這個(gè)我們不可以自定義,必須要和 RabbitMQ 中所支持的交換機(jī)類(lèi)型的名稱(chēng)保持一致才行。
4.5 路由 Key
定義:
路由 Key ,即 routing key ,交換機(jī)與頻道之間進(jìn)行綁定的 key ,通過(guò)這個(gè) key ,可以實(shí)現(xiàn)消息由交換機(jī)轉(zhuǎn)移至頻道的過(guò)程,從而實(shí)現(xiàn)消息的流轉(zhuǎn)。
在同一個(gè)虛擬主機(jī)中,不能存在相同路由 key 的 key 值。
代碼實(shí)現(xiàn):
我們應(yīng)該如何定義 routing key 呢?如下代碼所示:
channel.basicPublish("", "test_routing_key", null, msg.getBytes());
代碼解釋?zhuān)?/strong>
第 1 行,我們使用了 channel 的 basicPublish 方法,上述內(nèi)容中已經(jīng)對(duì)該方法進(jìn)行了介紹,現(xiàn)在讓我們直接來(lái)看該方法的第二個(gè)參數(shù),第二個(gè)參數(shù)表示我們路由 key 的名稱(chēng),這里為 test_routing_key 。
4.6 頻道
定義:
頻道,即 channel ,我們可以理解為傳遞消息的通道,在 RabbitMQ 中,消息最終經(jīng)過(guò) channel 發(fā)送給對(duì)應(yīng)的消費(fèi)者,消費(fèi)者接收到消息并將該消息進(jìn)行消費(fèi)。
代碼實(shí)現(xiàn):
我們應(yīng)該如何定義 channel 呢?如下代碼所示:
ConnectionFactory connectionFactory = new ConnectionFactory();
// 省略連接 RabbitMQ 服務(wù)器的配置
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
代碼解釋?zhuān)?/strong>
第 4 行,在由 ConnectionFactory 構(gòu)建出一個(gè)連接后,我們使用了 connection 的 createChannel 方法來(lái)通過(guò)建立好的連接創(chuàng)建一個(gè)頻道。
4.7 消息隊(duì)列
定義:
消息隊(duì)列,即消息所在的場(chǎng)所。在 RabbitMQ 中,不可能只存在一條消息,那么當(dāng)存在多條消息時(shí),RabbitMQ 會(huì)將這些消息組成一個(gè)隊(duì)列,用來(lái)存放同一領(lǐng)域下的消息,這個(gè)隊(duì)列就被稱(chēng)為消息隊(duì)列。
當(dāng)生成消息隊(duì)列時(shí),RabbitMQ 會(huì)根據(jù)不同的消息匹配策略,將不同領(lǐng)域的消息劃分到對(duì)應(yīng)的消息隊(duì)列中去。消費(fèi)者可以獲取消息隊(duì)列中的消息并消費(fèi),且我們可以通過(guò)設(shè)置一個(gè)閥值來(lái)規(guī)定我們同一時(shí)刻消費(fèi)者需要消費(fèi)的消息條數(shù),這在高并發(fā)環(huán)境中是很重要的。
5. 小結(jié)

本小節(jié)詳細(xì)介紹了 RabbitMQ 中的基礎(chǔ)核心概念,包括消息、虛擬主機(jī)、交換機(jī)、路由 Key 、頻道、消息隊(duì)列、生產(chǎn)者、消費(fèi)者,針對(duì)可以通過(guò)代碼實(shí)現(xiàn)的基礎(chǔ)核心概念,做了代碼實(shí)現(xiàn)和代碼解釋?zhuān)荚趲椭瑢W(xué)們?cè)趯?duì)理論知識(shí)有一定認(rèn)知的同時(shí),可以對(duì)相應(yīng)概念的代碼實(shí)現(xiàn)也有一個(gè)了解。
本小節(jié)是學(xué)習(xí) RabbitMQ 的基礎(chǔ),在學(xué)習(xí)本節(jié)內(nèi)容時(shí),一定要理清楚本節(jié)中所涉及的所有的概念,同學(xué)們只有對(duì)這些概念有所了解之后,才能開(kāi)始 RabbitMQ 的學(xué)習(xí),各位同學(xué)加油。