RabbitMQ學習(二)——AMQP協議

在上一篇博客中我們介紹了RabbitMQ的基本特性和安裝,本篇博文將會對RabbitMQ的基本知識進行介紹。主要包括以下幾點的知識介紹:

  • AMQP協議介紹
  • RabbitMQ中常用的基本術語
  • RabbitMQ的工作流程介紹

RabbitMQ是消息傳輸的中間者,可以把它當做是一個消息代理,你把消息傳送給它,它再把消息發送給具體的接收人。
這就像是郵局一樣,你把郵件放入郵箱當中,郵件員會把郵件發送給你的收件人。不同的是RabbitMQ是接受,存儲和轉發二進制數據塊——消息。

一、 AMQP協議

RabbitMQ是Advanced Message Queuing Protocol (AMQP,高級消息隊列協議)開放標準的實現,最新的RabbitMQ主要是基於AMQP 0-9-1來實現的。

AMQP(高級消息隊列協議)是一個網絡協議。它支持符合要求的客戶端應用(application)和消息中間件代理(messaging middleware broker)之間進行通信。主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。

說簡單點就是在異步通訊中,消息不會立刻到達接收方,而是被存放到一個容器中,當滿足一定的條件之後,消息會被容器發送給接收方,這個容器即消息隊列(MQ),而完成這個功能需要雙方和容器以及其中的各個組件遵守統一的約定和規則,AMQP就是這樣的一種協議,消息發送與接受的雙方遵守這個協議可以實現異步通訊。這個協議約同時規定了消息的格式和工作方式。

消息代理(message brokers)從發佈者(publishers)亦稱生產者(producers)那兒接收消息,並根據既定的路由規則把接收到的消息發送給處理消息的消費者(consumers)。

由於AMQP是一個網絡協議,所以這個過程中的發佈者,消費者,消息代理 可以存在於不同的設備上。

消息(message)被髮布者(publisher)發送給交換機(exchange),交換機常常被比喻成郵局或者郵箱。然後交換機將收到的消息根據路由規則分發給綁定的隊列(queue)。最後AMQP代理會將消息投遞給訂閱了此隊列的消費者,或者消費者按照需求自行獲取。

AMQP的機制如下圖所示:
AMQP

這是一個簡單的“Hello,world”示例,從發佈者到生成者消息的大致流向,其中還省略了一些AMQP實際的組件細節。這裏主要包括以下一些組件:

Publisher,數據的發送方。
Exchange,消息交換機,它指定消息按什麼規則,路由到哪個隊列,這裏的規則後面會有介紹。
Queue,消息隊列載體,每個消息都會被投入到一個或多個隊列。
Consumer,數據的接收方。

發佈者(Publisher)發佈消息時可以給消息指定各種消息屬性(message meta-data)。有些屬性有可能會被消息代理(Brokers)使用,然而其他的屬性則是完全不透明的,它們只能被接收消息的應用所使用。

從安全角度考慮,網絡是不可靠的,接收消息的應用也有可能在處理消息的時候失敗。基於此原因,AMQP模塊包含了一個消息確認(message acknowledgements)的概念:當一個消息從隊列中投遞給消費者後(Consumer),消費者會通知一下消息代理(Broker),這個可以是自動的,也可以由處理消息的應用的開發者執行。當“消息確認”被啓用的時候,消息代理不會完全將消息從隊列中刪除,直到它收到來自消費者的確認回執(acknowledgement)。

在某些情況下,例如當一個消息無法被成功路由時,消息或許會被返回給發佈者並被丟棄。或者,如果消息代理執行了延期操作,消息會被放入一個所謂的死信隊列中。此時,消息發佈者可以選擇某些參數來處理這些特殊情況。

隊列,交換機和綁定統稱爲AMQP實體(AMQP entities)。

以上這些是在上圖中顯示出來的一些AMQP組件元件,除了這些外,還有一些額外的概念,主要爲:
Binding,綁定,消息隊列與交換器直接關聯的,它的作用就是把Exchange和Queue按照路由規則綁定起來。

Routing Key,路由關鍵字,Exchange根據這個關鍵字進行消息投遞。

Channel,信道,多路複用連接中的一條獨立的雙向數據流通道,爲會話提供物理傳輸介質。Channel是在connection內部建立的邏輯連接,如果應用程序支持多線程,通常每個thread創建單獨的channel進行通訊,AMQP method包含了channel id幫助客戶端和message broker識別channel,所以channel之間是完全隔離的。Channel作爲輕量級的Connection極大減少了操作系統建立TCP connection的開銷。在客戶端的每個連接裏,可建立多個Channel,每個Channel代表一個會話任務。

Broker ,AMQP的服務端稱爲Broker。其實Broker就是接收和分發消息的應用,也就是說RabbitMQ Server就是Message Broker。

Virtual Host,虛擬主機,一批交換器(Exchange),消息隊列(Queue)和相關對象。虛擬主機是共享相同身份認證和加密環境的獨立服務器域。同時一個Broker裏可以開設多個vhost,用作不同用戶的權限分離。

Connection ,連接,一個網絡連接,比如TCP/IP套接字連接。Channel是建立在Connection之上的,一個Connection可以建立多個Channel。

Message,消息體,是AMQP所操縱的基本單位,它由Producer產生,經過Broker被Consumer所消費。它的基本結構有兩部分: Header和Body。Header是由Producer添加上的各種屬性的集合,這些屬性有控制Message是否可被緩存,接收的Queue是哪個,優先級是多少等。Body是真正需要傳送的數據,它是對Broker不可見的二進制數據流,在傳輸過程中不應該受到影響。

上面的簡單實例圖只是簡單說明了一些消息傳送的基本流程,可能其中的頻道、虛擬主機、連接、信道等都沒有體現出來。到後面RabbitMQ的知識點都會慢慢介紹到。

總的AMQP的結構圖如下所示:
AMQP

下面對AMQP的一些重要概念做詳細分析:

交換機(消息交換機)

交換機是用來發送消息的AMQP實體。交換機拿到一個消息之後將它路由給一個或零個隊列。它使用哪種路由算法是由交換機類型和被稱作綁定(bindings)的規則所決定的。

四種交換機:

  • Direct exchange(直連交換機)
  • Fanout exchange(扇型交換機)
  • Topic exchange(主題交換機)
  • Headers exchange(頭交換機)

交換機可以有兩個狀態:持久(durable)、暫存(transient)。持久化的交換機會在消息代理(Broker)重啓後依舊存在,而暫存的交換機則不會(它們需要在代理再次上線後重新被聲明)。然而並不是所有的應用場景都需要持久化的交換機。

不同的交換機的區別和用法,會在後面的文章中做介紹,這裏只需要知道有幾種類型的交換機就可以了。

交換機的幾個重要屬性:
Name
Durability (消息代理重啓後,交換機是否還存在)
Auto-delete (當所有與之綁定的消息隊列都完成了對此交換機的使用後,刪掉它)
Arguments(依賴代理本身)

隊列

AMQP中的隊列(Queue)跟其他消息隊列或任務隊列中的隊列是很相似的:它們存儲着即將被應用消費掉的消息。隊列跟交換機共享某些屬性,但是隊列也有一些另外的屬性。

Name
Durable(消息代理重啓後,隊列依舊存在)
Exclusive(只被一個連接(connection)使用,而且當連接關閉後隊列即被刪除)
Auto-delete(當最後一個消費者退訂後即被刪除)
Arguments(一些消息代理用他來完成類似與TTL的某些額外功能)

隊列在聲明(declare)後才能被使用。如果一個隊列尚不存在,聲明一個隊列會創建它。如果聲明的隊列已經存在,並且屬性完全相同,那麼此次聲明不會對原有隊列產生任何影響。如果聲明中的屬性與已存在隊列的屬性有差異,那麼一個錯誤代碼爲406的通道級異常就會被拋出。

隊列持久化
持久化隊列(Durable queues)會被存儲在磁盤上,當消息代理(broker)重啓的時候,它依舊存在。沒有被持久化的隊列稱作暫存隊列(Transient queues)。
持久化的隊列並不會使得路由到它的消息也具有持久性。倘若消息代理掛掉了,重新啓動,那麼在重啓的過程中持久化隊列會被重新聲明,無論怎樣,只有經過持久化的消息才能被重新恢復。(隊列持久化 ≠ 消息持久化)

綁定

綁定(Binding)是交換機(Exchange)將消息(Message)路由給隊列(Queue)所需遵循的規則。如果要指示交換機“E”將消息路由給隊列“Q”,那麼“Q”就需要與“E”進行綁定。綁定操作需要定義一個可選的路由鍵(Routing Key)屬性給某些類型的交換機。路由鍵的意義在於從發送給交換機的衆多消息中選擇出某些消息,將其路由給綁定的隊列。

打個比方:

隊列(Queue)是我們想要去的目的地
交換機(Exchange)是一個轉換站,比如車站
綁定(Binding)就是車站到目的地的路線。能夠到達目的地的路線可以是一條或者多條
擁有了交換機這個中間層,很多由發佈者直接到隊列難以實現的路由方案能夠得以實現,並且避免了應用開發者的許多重複勞動。

如果AMQP的消息無法路由到隊列(例如,發送到的交換機沒有綁定隊列),消息會被就地銷燬或者返還給發佈者。如何處理取決於發佈者設置的消息屬性。

虛擬主機

爲了在一個單獨的代理上實現多個隔離的環境(用戶、用戶組、交換機、隊列 等),AMQP提供了一個虛擬主機(virtual hosts - vhosts)的概念。這跟Web servers虛擬主機概念非常相似,這爲AMQP實體提供了完全隔離的環境。當連接被建立的時候,AMQP客戶端來指定使用哪個虛擬主機。

連接

AMQP連接通常是長連接。AMQP是一個使用TCP提供可靠投遞的應用層協議。AMQP使用認證機制並且提供TLS(SSL)保護。當一個應用不再需要連接到AMQP代理的時候,需要優雅的釋放掉AMQP連接,而不是直接將TCP連接關閉。

信道

有些應用需要與AMQP代理建立多個連接。無論怎樣,同時開啓多個TCP連接都是不合適的,因爲這樣做會消耗掉過多的系統資源並且使得防火牆的配置更加困難。AMQP 0-9-1提供了信道(channels)來處理多連接,可以把信道理解成共享一個TCP連接的多個輕量化連接。

在涉及多線程/進程的應用中,爲每個線程/進程開啓一個信道(channel)是很常見的,並且這些通道不能被線程/進程共享。

一個特定信道上的通訊與其他信道上的通訊是完全隔離的,因此每個AMQP方法都需要攜帶一個信道號,這樣客戶端就可以指定此方法是爲哪個信道準備的。

這裏只是簡單介紹了AMQP的一些重要的基本概念,這裏主要參考了RabbitMQ官方文檔和RabbitMQ的中方翻譯。因此有些比較好的概念就是直接參考的原文的文檔,這裏主要是爲了介紹清楚AMQP。讀者也可以參考原文檔,文檔鏈接:AMQP 0-9-1 簡介AMQP 0-9-1 Model Explained

二、RabbitMQ中常用的基本術語

之所以把這個提出來,是因爲好多人把AMQP和RabbitMQ弄混了,其實AMQP就是一個協議,而RabbitMQ把這個協議用Erlang實現出來了。所以AMQP中的概念就是指RabbitMQ中的基本概念,因此上文中的那些隊列、連接、信道、交換機等概念在RabbitMQ中是同樣的。

三、RabbitMQ的工作流程介紹

1、建立信息。Publisher定義需要發送消息的結構和內容。
2、建立Conection和Channel。由Publisher和Consumer創建連接,連接到Broker的物理節點上,同時建立Channel。Channel是建立在Connection之上的,一個Connection可以建立多個Channel。Publisher連接Virtual Host 建立Channel,Consumer連接到相應的Queue上建立Channel。
3、聲明交換機和隊列。聲明一個消息交換機(Exchange)和隊列(Queue),並設置相關屬性。
4、發送消息。由Publisher發送消息到Broker中的Exchange中
5、路由轉發。RabbitMQ收到消息後,根據​​消息指定的Exchange(交換機) 來查找Binding(綁定) 然後根據規則(Routing Key)分發到不同的Queue。這裏就是說使用Routing Key在消息交換機(Exchange)和消息隊列(Queue)中建立好綁定關係,然後將消息發送到綁定的隊列中去。
6、消息接收。Consumer監聽相應的Queue,一旦Queue中有可以消費的消息,Queue就將消息發送給Consumer端。
7、消息確認。當Consumer完成某一條消息的處理之後,需要發送一條ACK消息給對應的Queue。

Consumer收到消息時需要顯式的向RabbitMQ Broker發送basic.ack消息或者Consumer訂閱消息時設置auto_ack參數爲true。
在通信過程中,隊列對ACK的處理有以下幾種情況:

  • 如果Consumer接收了消息,發送ack,RabbitMQ會刪除隊列中這個消息,發送另一條消息給Consumer。
  • 如果Consumer接收了消息, 但在發送ack之前斷開Channel,RabbitMQ會認爲這條消息沒有被deliver(遞送),如果有其他的Channel,會該消息將被髮送給另外的Channel。如果沒有,當在Consumer再次連接的時候,這條消息會被redeliver(重新遞送)。
  • 如果consumer接收了消息,但是忘記了ack,RabbitMQ不會重複發送消息。
  • 新版RabbitMQ還支持Consumer reject某條(類)消息,可以通過設置requeue參數中的reject爲true達到目地,那麼Consumer將會把消息發送給下一個註冊的Consumer。
8、關閉消息通道(channel)以及和服務器的連接。

到此RabbitMQ的工作流程就走通了一遍,本篇介紹也到此結束。後面會對RabbitMQ的知識再進行總結介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章