領先一步
VMware 提供培訓和認證,助你加速提升。
瞭解更多更新 我修改了第一段,以闡明 RabbitMQ 和 JMS 之間的關係。
RabbitMQ 是一個輕量級、可靠、可擴充套件且可移植的訊息代理。但與許多 Java 開發者熟悉的訊息代理不同,它並非基於 JMS。相反,你的應用程式透過一種平臺中立的、線級別協議與其通訊:高階訊息佇列協議 (AMQP)。幸運的是,已經有 Java 客戶端庫,並且 SpringSource 正在致力於一流的 Spring 和 Grails 整合——所以不必擔心使用 RabbitMQ 需要進行底層操作。你甚至可以找到提供 JMS 介面的 AMQP 客戶端庫。但是 AMQP 在操作上與 JMS 有足夠的差異,這可能會讓習慣了 JMS 模型的 Java 開發者感到困惑。
為了簡化過渡,我將在本文中探討支撐 AMQP 的基本概念以及三種常見的用例場景。讀完本文後,你將有望對如何配置 RabbitMQ 並透過 Spring 和 Grails 提供的 API 來使用它有足夠的瞭解。
就像任何訊息系統一樣,AMQP 是一種處理釋出者和消費者的訊息協議。釋出者生成訊息,消費者接收並處理它們。訊息代理(如 RabbitMQ)的工作是確保釋出者的訊息傳送給正確的消費者。為此,代理使用兩個關鍵元件:交換機和佇列。下圖展示了它們如何連線釋出者和消費者
如你所見,這個設定相當直接。釋出者將訊息傳送到一個命名的交換機,消費者從佇列中拉取訊息(或者佇列根據配置將訊息推送到消費者)。當然,首先必須建立連線,那麼釋出者和消費者如何發現彼此呢?透過交換機的名稱。通常,釋出者或消費者之一會建立一個給定名稱的交換機,然後公開該名稱。如何公開取決於具體情況,但可以將其放在公共 API 文件中或傳送給已知客戶端。
訊息如何從交換機路由到佇列?這是個好問題。首先,佇列必須附加到指定的交換機。通常,消費者會在建立佇列的同時將其附加到交換機。其次,交換機收到的訊息必須與佇列匹配——這個過程稱為“繫結”。
為了理解繫結,瞭解 AMQP 訊息的結構很有幫助
訊息的頭部(headers)和屬性(properties)本質上是鍵/值對。它們之間的區別在於,頭部由 AMQP 規範定義,而屬性可以包含任意的、應用程式特定的資訊。實際的訊息內容只是一系列位元組,所以如果你想在訊息中傳遞文字,那麼應該標準化編碼方式。UTF-8 是一個不錯的選擇。你可以在訊息頭部指定內容型別和編碼,但顯然這並不是特別常見。
這與繫結有什麼關係?其中一個標準頭部叫做路由鍵 (routing-key)代理就是用它來將訊息與佇列匹配的。每個佇列指定一個“繫結鍵”,如果該鍵與路由鍵 (routing-key)頭部的值匹配,佇列就會收到訊息。
由於交換機型別的概念,事情變得稍微複雜。AMQP 規範定義了以下四種類型
交換機型別 | 行為 |
---|---|
Direct (直接) | 繫結鍵必須與路由鍵完全匹配——不支援萬用字元。 |
Topic (主題) | 與 Direct 相同,但繫結鍵中允許使用萬用字元。'#' 匹配零個或多個用點分隔的單詞,而 '*' 精確匹配一個這樣的單詞。 |
Fanout (扇出) | 路由鍵和繫結鍵被忽略——所有釋出的訊息都會發送到所有繫結的佇列。 |
Headers (頭部) |
更新 我更正了關於萬用字元的資訊,它們是基於點分隔的單詞或術語工作的。
例如,假設釋出者將路由鍵為 "NYSE" 的訊息傳送到名為 "Stocks" 的主題交換機。如果消費者建立一個附加到 "Stocks" 的佇列,並使用繫結鍵 "#"、"*" 或 "NYSE",那麼該消費者將收到訊息,因為這三個繫結鍵都匹配 "NYSE"。然而,如果訊息釋出到 direct 交換機,那麼如果繫結鍵是 "#" 或 "*",消費者將不會收到訊息,因為這些字元將被視為字面值,而不是萬用字元。有趣的是,儘管路由鍵中沒有點,"#.#" 也會匹配 "NYSE"。
現在考慮一條路由鍵為 "NYSE.TECH.MSFT" 的訊息。鑑於訊息將傳送到 topic 交換機,哪些繫結鍵會匹配它?
繫結鍵 | 匹配? |
---|---|
NYSE.TECH.MSFT | 是 |
# | 是 |
NYSE.# | 是 |
*.* | 否 |
NYSE.* | 否 |
NYSE.TECH.* | 是 |
NYSE.*.MSFT | 是 |
這就是所有要點。每個佇列支援多個消費者以及每個交換機支援多個佇列提供了靈活性。事實上,一個佇列甚至可以繫結到多個交換機。現在讓我們看看其中的一些場景。
AMQP 代理可以充當客戶端和服務之間的 RPC 機制。一般的設定是這樣的,使用一個 direct 交換機
一般的順序如下
從客戶端的角度來看,呼叫可以是阻塞的或非阻塞的。然而,實現其中一種的難易程度取決於所使用的客戶端庫。
RPC 場景的關鍵是確保客戶端和服務為初始請求使用相同的交換機,並且客戶端知道路由鍵應該指定什麼。
至於回覆佇列,它通常由客戶端建立,然後客戶端填充reply_to頭部。另外,雖然你可以為回覆使用與請求不同的交換機,但更常見的是請求和回覆都使用同一個交換機。
JMS 有主題佇列的概念,確保釋出者的訊息傳送給所有訂閱者。在 AMQP 中,透過將多個佇列繫結到一個交換機,你可以輕鬆實現相同的行為,如下所示
更好的是,佇列可以透過繫結鍵過濾它們接收的訊息。如果消費者想接收所有訊息,則可以指定繫結鍵為 "#"——即“匹配任意數量單詞”的萬用字元。對於普通開發者來說,有點令人困惑的是,正如前面提到的,"*" 匹配零個或一個(點分隔的)單詞。
想象你的應用程式有一堆需要執行的任務。使用 AMQP,你可以連線多個消費者,使得每個任務只分配給其中一個消費者。釋出者不關心是哪個消費者完成了工作,只關心工作被完成。這就是工作分發。
配置它非常簡單,如下圖所示
因此,你有一個繫結到交換機的佇列,多個消費者共享該佇列。無論有多少消費者,這種設定保證了只有一位消費者處理特定的訊息。
這些是 AMQP 代理的三種主要使用模式。雖然我分別描述了它們,但將它們組合起來使用是相當普遍的。例如,在 RPC 模式中,可以有多個服務共享同一個佇列(工作分發)。如何配置交換機和佇列完全取決於你,現在你應該對如何為你的情況找到合適的設定有了足夠的瞭解。
如果你想進一步深入瞭解 AMQP,可以查閱規範本身,特別是關於 General Architecture(總體架構)的部分。要開始使用 RabbitMQ,只需訪問其網站。