理解 RabbitMQ Exchange
來自專欄 杏仁技術站
作者 | 喬宇
杏仁後端工程師,關注服務端技術。
AMQP 簡介
在了解 RabbitMQ 的 Exchange(交換機)的概念之前,我們首先要對 RabbitMQ 相關的概念和名詞有一個大概的了解,RabbitMQ 是 AMQP(高級消息隊列協議)的標準實現:
從 AMQP 協議可以看出,Queue、Exchange 和 Binding 構成了 AMQP 協議的核心
- Producer:消息生產者,即投遞消息的程序。
- Broker:消息隊列伺服器實體。
- Exchange:消息交換機,它指定消息按什麼規則,路由到哪個隊列。
- Binding:綁定,它的作用就是把 Exchange 和 Queue 按照路由規則綁定起來。
- Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列。
- Consumer:消息消費者,即接受消息的程序。
Exchange 簡介
那麼為什麼我們需要 Exchange 而不是直接將消息發送至隊列呢?
AMQP 協議中的核心思想就是生產者和消費者的解耦,生產者從不直接將消息發送給隊列。生產者通常不知道是否一個消息會被發送到隊列中,只是將消息發送到一個交換機。先由 Exchange 來接收,然後 Exchange 按照特定的策略轉發到 Queue 進行存儲。Exchange 就類似於一個交換機,將各個消息分發到相應的隊列中。
在實際應用中我們只需要定義好 Exchange 的路由策略,而生產者則不需要關心消息會發送到哪個 Queue 或被哪些 Consumer 消費。在這種模式下生產者只面向 Exchange 發布消息,消費者只面向 Queue 消費消息,Exchange 定義了消息路由到 Queue 的規則,將各個層面的消息傳遞隔離開,使每一層只需要關心自己面向的下一層,降低了整體的耦合度。
理解 Exchange
Exchange 收到消息時,他是如何知道需要發送至哪些 Queue 呢?這裡就需要了解 Binding 和 RoutingKey 的概念:
Binding 表示 Exchange 與 Queue 之間的關係,我們也可以簡單的認為隊列對該交換機上的消息感興趣,綁定可以附帶一個額外的參數 RoutingKey。Exchange 就是根據這個 RoutingKey 和當前 Exchange 所有綁定的 Binding 做匹配,如果滿足匹配,就往 Exchange 所綁定的 Queue 發送消息,這樣就解決了我們向 RabbitMQ 發送一次消息,可以分發到不同的 Queue。RoutingKey 的意義依賴於交換機的類型。
下面就來了解一下 Exchange 的三種主要類型:Fanout
、Direct
和 Topic
。
Fanout Exchange
Fanout Exchange 會忽略 RoutingKey 的設置,直接將 Message 廣播到所有綁定的 Queue 中。
應用場景
以日誌系統為例:假設我們定義了一個 Exchange 來接收日誌消息,同時定義了兩個 Queue 來存儲消息:一個記錄將被列印到控制台的日誌消息;另一個記錄將被寫入磁碟文件的日誌消息。我們希望 Exchange 接收到的每一條消息都會同時被轉發到兩個 Queue,這種場景下就可以使用 Fanout Exchange 來廣播消息到所有綁定的 Queue。
Direct Exchange
Direct Exchange 是 RabbitMQ 默認的 Exchange,完全根據 RoutingKey 來路由消息。設置 Exchange 和 Queue 的 Binding 時需指定 RoutingKey(一般為 Queue Name),發消息時也指定一樣的 RoutingKey,消息就會被路由到對應的Queue。
應用場景
現在我們考慮只把重要的日誌消息寫入磁碟文件,例如只把 Error 級別的日誌發送給負責記錄寫入磁碟文件的 Queue。這種場景下我們可以使用指定的 RoutingKey(例如 error)將寫入磁碟文件的 Queue 綁定到 Direct Exchange 上。
Topic Exchange
Topic Exchange 和 Direct Exchange 類似,也需要通過 RoutingKey 來路由消息,區別在於Direct Exchange 對 RoutingKey 是精確匹配,而 Topic Exchange 支持模糊匹配。分別支持*
和#
通配符,*
表示匹配一個單詞,#
則表示匹配沒有或者多個單詞。
應用場景
假設我們的消息路由規則除了需要根據日誌級別來分發之外還需要根據消息來源分發,可以將 RoutingKey 定義為 消息來源.級別
如 order.info
、user.error
等。處理所有來源為 user
的 Queue 就可以通過 user.*
綁定到 Topic Exchange 上,而處理所有日誌級別為 info
的 Queue 可以通過 *.info
綁定到 Exchange上。
兩種特殊的 Exchange
Headers Exchange
Headers Exchange 會忽略 RoutingKey 而根據消息中的 Headers 和創建綁定關係時指定的 Arguments 來匹配決定路由到哪些 Queue。
Headers Exchange 的性能比較差,而且 Direct Exchange 完全可以代替它,所以不建議使用。
Default Exchange
Default Exchange 是一種特殊的 Direct Exchange。當你手動創建一個隊列時,後台會自動將這個隊列綁定到一個名稱為空的 Direct Exchange 上,綁定 RoutingKey 與隊列名稱相同。有了這個默認的交換機和綁定,使我們只關心隊列這一層即可,這個比較適合做一些簡單的應用。
總結
在 Exchange 的基礎上我們可以通過比較簡單的配置綁定關係來靈活的使用消息路由,在簡單的應用中也可以直接使用 RabbitMQ 提供的 Default Exchange 而無需關心 Exchange 和綁定關係。Direct Exchange、Topic Exchange、Fanout Exchange 三種類型的交換機的使用方式也很簡單,容易掌握。
全文完
歡迎搜索關注微信公眾號:杏仁技術站(微信號 xingren-tech)。
我們正在招聘Java工程師,歡迎有興趣的同學投遞簡歷到 rd-hr@xingren.com
推薦閱讀:
※消息隊列怎樣不丟消息?
※Spring 整合JMS 基於ActiveMQ 實現消息的發送接收
※螞蟻消息中間件 (MsgBroker) 在 YGC 優化上的探索
※調用:RPC MQ
※消息隊列的冪等性