什么是消息隊列(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:
brew update
接著安裝 RabbitMQ 即可,安裝過程中會自動安裝其所依賴的 Erlang。
2、運行
RabbitMQ 的啟動運行很簡單,找到其安裝目錄后(使用 Homwbrew 安裝的默認目錄為:/usr/local/Cellar/rabbitmq),進入到目錄的 sbin 目錄下,可以看到有 6 個
以 rabbitmq 開頭的可執行文件,直接執行 rabbitmq-server 即可。
啟動正常的話可以看到啟動過程的日志信息和最后的 completed with 6 plugins,這也說明啟動的時候默認加載了 6 個插件。
此時通過瀏覽器訪問 http://localhost:15672 可以看到其管理界面(默認用戶名和密碼都是 guest),可以在 admin 選項卡頁面新增用戶,管理界面如下:
PS: 以上方式不是后臺啟動,如果想讓 RabbitMQ 后臺守護進程的方式啟動的話,可以在啟動的時候加上 -detached 參數。
3、查詢服務器狀態
在安裝目錄的 sbin 下面有個可執行文件 rabbitmqctl ,它提供了 RabbitMQ 管理需要的幾乎一站式解決方案,絕大部分的運維命令它都可以提供。查詢 RabbitMQ 服務器的狀態信息可以用參數 status。
RabbitMQ 中的基礎概念
1、消息模型 幾乎所有的 MQ 抽象來說都是一樣的過程:消費者訂閱某個隊列,生產者生產消息,然后發布到隊列中,最后將消息發送到監聽該隊列的消費者那里。如下圖所示:
2、基本概念 上面上一個消息隊列的抽象概述,具體到 RabbitMQ 有一些特有的概念,RabbitMQ 是 AMQP 協議的一個開源實現,其內部概念大都是 AMQP 協議的一些概念。
名稱 | 描述 |
---|---|
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 決定交換器的消息應該發到哪個隊列。
4、Exchange 類型 Exchange 分發消息時根據類型的不同分發策略略有區別,目前共有四種類型:direct、fanout、topic、headers。headers 匹配 AMQP 消息的 header 而不是路由鍵,此外 headers 交換器和 direct 交換器完全一致,但性能差很多,目前幾乎用不到了,所以直接看另外三種類型即可。
4.1、direct 類型
消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致,交換器就將消息發到對應的隊列中。路由鍵與隊列名完全匹配,如果一個隊列綁定到交換機要求路由鍵為 "dog",則只轉發 routing key 標記為 “dog” 的消息,不會轉發 "dog.puppy",也不會轉發 "dog.guard" 等等。它是完全匹配、單播的模式。
4.2、fanout 類型
每個發到 fanout 類型交換機的消息都會發到所有綁定的隊列上去。fanout 交換器不處理路由鍵,只是簡單的將隊列綁定到交換器上,每個發送到交換器的消息都會被轉發到與該交換器綁定的所有隊列上。很像子網廣播,每臺子網內的主機都獲得一份復制的消息。fanout 類型轉發消息是最快的。
3、topic 類型
topic 交換器通過模式匹配分配消息的路由鍵屬性,將路由鍵和某個模式進行匹配,此時隊列需要綁定到一個模式上,它將路由鍵和綁定的字符串切分成單詞,這些單詞之間用點隔開。它同樣也識別兩個通配符:符號 "#" 和符號 ""。# 符號匹配 0 個或多個單詞, 符號匹配不多不少一個單詞。
總結
本文主要講了關于 RabbitMQ 的安裝以及基礎概念的相關介紹,由于它是基于 Erlang 語言開發,可能對于部分 Java 開發者想了解其底層實現細節以及排查比較復雜的問題時不是很友好。