RabbitMQ 入門之基礎概念
阿新 • • 發佈:2020-07-18
#### 什麼是訊息佇列(MQ)
訊息是在不同應用間傳遞的資料。這裡的訊息可以非常簡單,比如只包含字串,也可以非常複雜,包含多個巢狀的物件。訊息佇列(Message Queue)簡單來說就是一種應用程式間的通訊方式,訊息傳送後立即返回,然後由訊息系統保證訊息的可靠性傳輸,訊息生產者只需要把訊息發到 MQ 中就可以了,不需要關心訊息的消費,同樣,訊息消費者只管從 MQ 中拉取訊息而不管是誰生產的訊息,通過這樣的一個“互相不知道物件存在”模式,將訊息的生產者和訊息的消費者解耦了。
#### 什麼場景下考慮使用訊息佇列
從上面可以知道,訊息佇列是一種應用間的非同步協作機制,那麼我們什麼時候需要用到 MQ 呢?以常見的訂單系統為例,當用戶點選「下單」後的業務邏輯可能包括:扣減庫存、生成相應訂單資料、發簡訊通知等。在專案和業務發展初期上面這些邏輯可能放在一起執行,隨著業務的發展訂單量的增加,需要提升系統服務的效能,此時就可以將一些不需要立即生效的操作拆分出來非同步執行,比如傳送簡訊通知等。這種場景下就可以使用 MQ ,在下單主流程(比如扣減庫存、生成訂單資料等)完成之後傳送一條訊息到 MQ 讓主流程快速走完,然後由另外一個執行緒拉取 MQ 的訊息,執行相應的業務邏輯。這裡的例子主要是用訊息佇列來解耦。
#### RabbitMQ 的特點
RabbitMQ 是一個由 Relang 語言開發的 AMQP 的開源實現。AMQP(Advanced Message Queue:高階訊息佇列協議)它是應用層協議的一個開放標準,為面向訊息的中介軟體設計,基於此協議的客戶端與訊息中介軟體可傳遞訊息,並不受產品、開發語言等條件的限制。RabbitMQ 最初起源於訊息系統,用於在分散式系統中儲存轉發訊息,具體有如下一些特點:
- **可靠性:** RabbitMQ 使用一些機制來保證可靠性,比如持久化、傳輸確認機制(ack)和釋出確認等。
- **靈活的路由策略:** 在訊息進入佇列之前,通過 Exchange 來路由訊息,對於典型的路由功能,RabbitMQ 已經提供了一些內建的 Exchange 來實現。針對複雜的路由功能,可以將多個 Exchange 綁在一起,也通過外掛機制實現自己的 Exchange。
- **訊息叢集:** 多個 RabbitMQ 伺服器可以組成一個叢集,形成一個邏輯 Broker。
- **高可用:** 佇列可以在叢集中的叢集上進行映象,使得在部分節點出問題的情況下佇列仍然可用。
- **多種協議:** RabbitMQ 支援多種訊息佇列協議,比如 STOMP、MQTT 等。
- **多語言客戶端:** RabbitMQ 幾乎支援多有常用的語言,比如:Java、.NET 等
- **管理介面:** RabbitMQ 提供了一個易用的使用者介面,使得使用者可以監控和管理訊息 Broker 的許多方面。
#### RabbitMQ 安裝(mac)和執行
**1、安裝**
因為 RabbitMQ 依賴於 Erlang 語言,所以在安裝 RabbitMQ 之前需要先安裝 Erlang 環境,但是由於是 Mac 環境,可以使用 HomeBrew 安裝,安裝前先更新 brew:
```bash
brew update
```
接著安裝 RabbitMQ 即可,安裝過程中會自動安裝其所依賴的 Erlang。
![rabbitmq-base-7.jpeg](https://i.loli.net/2020/07/18/OoSVmkX3v6jf7dC.jpg)
**2、執行**
RabbitMQ 的啟動執行很簡單,找到其安裝目錄後(使用 Homwbrew 安裝的預設目錄為:/usr/local/Cellar/rabbitmq),進入到目錄的 sbin 目錄下,可以看到有 6 個
以 rabbitmq 開頭的可執行檔案,直接執行 rabbitmq-server 即可。
![rabbitmq-base-8.jpeg](https://i.loli.net/2020/07/18/pRksb1wcINlM2zF.jpg)
啟動正常的話可以看到啟動過程的日誌資訊和最後的 completed with 6 plugins,這也說明啟動的時候預設載入了 6 個外掛。
![rabbitmq-base-9.jpeg](https://i.loli.net/2020/07/18/Mr8h2labI7fyovW.jpg)
此時通過瀏覽器訪問 [http://localhost:15672](http://localhost:15672/) 可以看到其管理介面(預設使用者名稱和密碼都是 guest),可以在 admin 選項卡頁面新增使用者,管理介面如下:
![rabbitmq-base-10.jpeg](https://i.loli.net/2020/07/18/Dd9mAj34BuiERrk.jpg)
**PS:** 以上方式不是後臺啟動,如果想讓 RabbitMQ 後臺守護程序的方式啟動的話,可以在啟動的時候加上 -detached 引數。
![rabbitmq-base-11.jpeg](https://i.loli.net/2020/07/18/VDIkLgZ2QuR8liz.jpg)
**3、查詢伺服器狀態**
在安裝目錄的 sbin 下面有個可執行檔案 rabbitmqctl ,它提供了 RabbitMQ 管理需要的幾乎一站式解決方案,絕大部分的運維命令它都可以提供。查詢 RabbitMQ 伺服器的狀態資訊可以用引數 status。
![rabbitmq-base-12.jpeg](https://i.loli.net/2020/07/18/4lukrMOYfIhaFmJ.jpg)
#### RabbitMQ 中的基礎概念
**1、訊息模型** 幾乎所有的 MQ 抽象來說都是一樣的過程:消費者訂閱某個佇列,生產者生產訊息,然後釋出到佇列中,最後將訊息傳送到監聽該佇列的消費者那裡。如下圖所示:
![rabbitmq-base-1.jpeg](https://i.loli.net/2020/07/18/gopHO9vEchYbmSG.jpg)
**2、基本概念** 上面上一個訊息佇列的抽象概述,具體到 RabbitMQ 有一些特有的概念,RabbitMQ 是 AMQP 協議的一個開源實現,其內部概念大都是 AMQP 協議的一些概念。
![rabbitmq-base-2.jpeg](https://i.loli.net/2020/07/18/LpzNB6Vyo4CdDJW.jpg)
| **名稱** | **描述** |
| :---: | :---: |
| Message 訊息 | 訊息是不具名的,它由訊息頭和訊息體組成。訊息體是不透明的,而訊息頭則是由一系列的可選屬性組成,這些屬性包括 routing-key(路由鍵)、priority(相對於其它訊息的優先權)、delivery-mode(指出該訊息可能需要永續性儲存)等。 |
| Publisher 訊息生產者 | 一個向交換機發送訊息的客戶端應用程式。 |
| Exchange 交換器 | 用來接收生產者傳送過來的訊息,並將這些訊息傳送給伺服器中的佇列。 |
| Binding 繫結 | 用於訊息佇列和交換器之間的關聯,一個繫結就是一個基於路由鍵將交換器和訊息佇列連線起來的路由規則,所以可以將交換器理解成一個由繫結構成的路由表。 |
| Queue 訊息佇列 | 用來儲存訊息直到傳送給消費者,它是訊息的容器,也是訊息的終點,一個訊息可投入一個或多個佇列,訊息一直在佇列裡面,等待消費者連線到這個佇列並將其取走。 |
| Connection 網路連線 | 比如一個 TCP 連線。 |
| Channel 通道 | 多路複用連線中的一條獨立雙向資料流通道,通道是建立在真實 TCP 連線內的虛擬連線,AMQP 命令都是通過通道傳送出去的,不管是釋出訊息、訂閱訊息還是接收訊息,這些動作都是通過通道完成的。因為對於作業系統來說建立和銷燬 TCP 都是非常昂貴的開銷,所以引入了通道的概念,以複用一條 TCP 連線。 |
| Consumer 訊息的消費者 | 一個從訊息佇列中獲取訊息的客戶端應用程式。 |
| Virtual Host 虛擬主機 | 表示一批交換器、訊息佇列和相關物件。虛擬主機是共享相同身份認證和加密環境的對伺服器域。每個 vhost 本質上是一個 mini 版的 RabbitMQ 伺服器,擁有自己的佇列、交換器、繫結和許可權機制。vhost 是 AMQP 概念的基礎,必須在連線時指定,RabbitMQ 預設的 vhost 是 / 。 |
**3、AMQP 中的訊息路由** AMQP 中訊息路由過程和 Java 開發者熟悉的 JMS 存在一些差別,AMQP 中增加了 Exchange 和 Binding 的角色。生產者把訊息傳送到 Exchange 上,訊息最終到達佇列並被消費者接收,而 Binding 決定交換器的訊息應該發到哪個佇列。
![rabbitmq-base-3.jpeg](https://i.loli.net/2020/07/18/sORwrQAXati3F5H.jpg)
**4、Exchange 型別** Exchange 分發訊息時根據型別的不同分發策略略有區別,目前共有四種類型:direct、fanout、topic、headers。headers 匹配 AMQP 訊息的 header 而不是路由鍵,此外 headers 交換器和 direct 交換器完全一致,但效能差很多,目前幾乎用不到了,所以直接看另外三種類型即可。
**4.1、direct 型別**
![rabbitmq-base-4.jpeg](https://i.loli.net/2020/07/18/7amFw9g5VnkRlJO.jpg)
訊息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致,交換器就將訊息發到對應的佇列中。路由鍵與佇列名完全匹配,如果一個佇列繫結到交換機要求路由鍵為 "dog",則只轉發 routing key 標記為 “dog” 的訊息,不會轉發 "dog.puppy",也不會轉發 "dog.guard" 等等。它是完全匹配、單播的模式。
**4.2、fanout 型別**
![rabbitmq-base-5.jpeg](https://i.loli.net/2020/07/18/8IADrG5voFPEqSb.jpg)
每個發到 fanout 型別交換機的訊息都會發到所有繫結的佇列上去。fanout 交換器不處理路由鍵,只是簡單的將佇列繫結到交換器上,每個傳送到交換器的訊息都會被轉發到與該交換器繫結的所有佇列上。很像子網廣播,每臺子網內的主機都獲得一份複製的訊息。fanout 型別轉發訊息是最快的。
**3、topic 型別**
![rabbitmq-base-6.jpeg](https://i.loli.net/2020/07/18/D8Wy2mT3FrVzOdg.jpg)
topic 交換器通過模式匹配分配訊息的路由鍵屬性,將路由鍵和某個模式進行匹配,此時佇列需要繫結到一個模式上,它將路由鍵和繫結的字串切分成單詞,這些單詞之間用點隔開。它同樣也識別兩個萬用字元:符號 "#" 和符號 "*"。# 符號匹配 0 個或多個單詞,* 符號匹配不多不少一個單詞。
#### 總結
本文主要講了關於 RabbitMQ 的安裝以及基礎概念的相關介紹,由於它是基於 Erlang 語言開發,可能對於部分 Java 開發者想了解其底層實現細節以及排查比較複雜的問題時不是很友好。