“訊息佇列”是在訊息的傳輸過程中儲存訊息的容器。
“訊息”是在兩臺計算機間傳送的資料單位。訊息可以非常簡單,例如只包含文字字串;也可以更復雜,可能包含嵌入物件。
訊息被髮送到佇列中。“訊息佇列”是在訊息的傳輸過程中儲存訊息的容器。訊息佇列管理器在將訊息從它的源中繼到它的目標時充當中間人。佇列的主要目的是提供路由並保證訊息的傳遞;如果傳送訊息時接收者不可用,訊息佇列會保留訊息,直到可以成功地傳遞它。
一般的訊息佇列是基於生產者-消費者模型。用於實時性要求並不是那麼高、非同步通訊的場景。
AMQP模型
AMQP(AdvancedMessageQueuingProtocal,高階訊息佇列協議)是一個提供統一非同步訊息傳遞服務的應用層標準高階訊息佇列協議,是應用層協議的一個開放標準,為面向訊息的中介軟體而設計。基於此協議的客戶端與訊息中介軟體可傳遞訊息,並不受客戶端/中介軟體不同產品、不同開發語言等條件的限制。
運作過程
左邊的客戶端向右邊的客戶傳送訊息,流程如下:
- 獲取Connection(客戶端到MQ伺服器的TCP鏈路)
- 獲取Channel(邏輯層的鏈路,基於Conncetion)
- 定義交換器、佇列
- 使用一個RoutingKey將佇列繫結到一個交換器
- 通過指定一個交換器和一個RoutingKey來訊息傳送到對應的佇列上
- 接收方在接受時也是獲取Connection,接著獲取Channel,然後指定一個佇列直接到它關心的佇列上取訊息,它對交換器、RoutingKey及如何繫結都不關心,到對應的對列上取訊息就行了
名詞解釋
在該模型中,三個主要功能模組連線成一個處理鏈完成預期的功能:
- exchange(交換器):接收發布應用程式傳送的訊息,並根據一定的規則將這些訊息路由到“訊息佇列”。
- message queue(訊息佇列):儲存訊息,直到這些訊息被消費者安全處理完為止。
- binding(繫結器):定義了exchange和message queue之間的關聯,提供路由規則。
Exchange本身不保持訊息,只是起到路由的作用,Exchange接收訊息生產者(MessageProducer)傳送的訊息根據不同的路由演算法將訊息傳送往MessageQueue。MessageQueue會在訊息不能被正常消費時快取這些訊息,具體的快取策略由實現者決定,當MessageQueue與訊息消費者(Messageconsumer)之間的連線通暢時,MessageQueue會將訊息轉發到consumer。
一個Broker(AMQP伺服器)中會存在多個MessageQueue?Exchange怎樣知道它要把訊息傳送到哪個MessageQueue中去呢?圖8-1中的Binding就是通過繫結Exchange與MessageQueue來解決這個問題。訊息應用者(ClientApplication)控制Exchange與某個特定MessageQueue繫結,並將這個MessageQueue接受何種特定訊息的條件繫結到Exchange,這個條件也叫Bindingkey或Criteria。AMQP協議的架構如下圖示意。
該圖(VirtualHost)用來指Exchange和MessageQueue組成的集合。它是一個虛擬概念,一個虛擬主機可以是一臺伺服器,還可以是由多臺伺服器組成的叢集,還可以是一些虛擬機器組成的叢集,上面執行一些Exchange和MessageQueue。
下面詳細解釋一下AMQP的工作原理:
從上圖看,Message是AMQP所操縱的基本單位,它由Producer產生,經過Broker被Consumer所消費。它的基本結構有兩部分:Header和Body。Header是由Producer新增上的各種屬性的集合,這些屬性有:控制Message是否可被快取,接收的Queue是哪個,優先順序是多少等。Body是真正需要傳送的資料,它是對Broker不可見的二進位制資料流,在傳輸過程中不應該受到影響。
一個Exchange在與多個MessageQueue通過繫結後,Exchange中就會存在一個路由表,這個表中儲存著每個MessageQueue所需要訊息的限制條件。Exchange就會檢查它接收到的每個Message的Header及Body資訊,來決定將Message路由到哪個Queue中去。每個Message的Header中應該有個屬性叫RoutingKey,它由Message傳送者產生,提供給Exchange路由這條資訊的標準。Exchange根據不同路由演算法有不同有ExchangeType。
- Direct型別,需要BindingKey等於RoutingKey。也就是1對1模式。
- Topic型別,所有符合RoutingKey(可以是一個表示式)RoutingKey所繫結的佇列可以接受訊息。相當於通過RoutingKey進行了過濾。
- Fanout型別,忽略BindingKey和RoutingKey,訊息傳遞到所有繫結的MessageQueue。即所有繫結此交換器的佇列都可以接收訊息,典型的訂閱/釋出模型。
- 也可以根據Message包含的某些屬性來判斷。
這些基礎的路由演算法由AMQP提供,當然ClientApplication也可以自定義各種自己的擴充套件路由演算法。
當Exchange按照一定的路由演算法把訊息發到MessageQueue後,作為訊息的儲存和分發實體,MessageQueue會把訊息快取到記憶體或硬碟中,並且按照順序把這些訊息發給一個或者多個訊息的消費者。
MQ在實際專案中的使用
openStack中的MQ
OpenStack遵循這樣的設計原則:專案之間通過RESTful API進行通訊;專案內部,不同服務程式之間的通訊,則必須要通過訊息匯流排。這種設計思想保證了各個專案對外提供服務的介面可以被不同型別的客戶端高效支援,同時也保證了專案內部通訊介面的可擴充套件性和可靠性,以支援大規模的部署。
軟體從最初的程式導向,物件導向,再到面向服務(SOA),要求我們去考慮各個服務之間如何傳遞訊息。借鑑硬體匯流排的概念,訊息匯流排的模式被引入,顧名思義,一些服務向匯流排傳送訊息,其他服務從匯流排上獲取訊息。
OpenStack oslo.messageing庫實現了以下兩種方式來完成專案內部各服務程式之間的通訊:
遠端過程呼叫(RPC,Remote Procedure Call)
通過遠端過程呼叫,一個服務程式可以呼叫其他遠端服務程式方法,並且有兩種呼叫方式:call和cast。call 則是同步執行的,呼叫者會被阻塞直到結果返回;cast 則是非同步執行,結果不會立刻被返回,呼叫者也不會被阻塞,但是呼叫者需要利用其他方式查詢這次遠端呼叫的結果。
事件通知(Event Notification)
某個服務程式可以把事件通知傳送到訊息匯流排上,該訊息匯流排上所有對此類事件感興趣的服務程式,都可以獲得此事件通知並進行一步的處理,處理的結果並不會返回給事件傳送者。這種通訊方式,不但可以在同一個專案內部的各個服務程式之間傳送通知,也可以實現跨專案之間的通知傳送。Ceilometer就通過這種方式大量獲取其他OpenStack專案的事件通知,從而進行計量和監控。
OpenStack中的通訊方式
AMQP
OpenStack中所支援的訊息匯流排型別中,大部分都是基於AMQP的。前面已經提到過了,故不贅述。
基於AMPQ實現RPC
配圖解釋:
- 客戶端傳送一個請求訊息給Exchange,指定routing key為"op_queue",同時指明一個訊息佇列名用來獲取響應,圖中為"res_queue",同時指明一個訊息佇列名用來獲取響應。在圖中為"res_queue"
- Exchange把此訊息轉發到訊息佇列op_queue
- 訊息佇列op_queue把訊息推送給服務端,服務端執行此RPC呼叫對應的任務。執行結束後,服務端把相應結果傳送給訊息佇列,指明routing key為"res_queue"
- Exchange 把此訊息轉發到訊息佇列res_queue
- 客戶端從訊息佇列res_queue中獲取響應。
小結
對於MQ中的概念進行了簡單的介紹。之後還會進行一定的擴充——比如在一些常見應用中MQ的應用。