“消息隊列”是在消息的傳輸過程中保存消息的容器趾牧。
“消息”是在兩臺計算機間傳送的數(shù)據(jù)單位宏蛉。消息可以非常簡單,例如只包含文本字符串庭砍;也可以更復雜场晶,可能包含嵌入對象。
消息被發(fā)送到隊列中怠缸∈幔“消息隊列”是在消息的傳輸過程中保存消息的容器。消息隊列管理器在將消息從它的源中繼到它的目標時充當中間人揭北。隊列的主要目的是提供路由并保證消息的傳遞扳炬;如果發(fā)送消息時接收者不可用,消息隊列會保留消息搔体,直到可以成功地傳遞它恨樟。
一般的消息隊列是基于生產(chǎn)者-消費者模型。用于實時性要求并不是那么高疚俱、異步通信的場景劝术。
AMQP模型
AMQP(AdvancedMessageQueuingProtocal,高級消息隊列協(xié)議)是一個提供統(tǒng)一異步消息傳遞服務的應用層標準高級消息隊列協(xié)議呆奕,是應用層協(xié)議的一個開放標準养晋,為面向消息的中間件而設計〉锹基于此協(xié)議的客戶端與消息中間件可傳遞消息匙握,并不受客戶端/中間件不同產(chǎn)品、不同開發(fā)語言等條件的限制陈轿。
運作過程
左邊的客戶端向右邊的客戶發(fā)送消息圈纺,流程如下:
- 獲取Connection(客戶端到MQ服務器的TCP鏈路)
- 獲取Channel(邏輯層的鏈路秦忿,基于Conncetion)
- 定義交換器、隊列
- 使用一個RoutingKey將隊列綁定到一個交換器
- 通過指定一個交換器和一個RoutingKey來消息發(fā)送到對應的隊列上
- 接收方在接受時也是獲取Connection蛾娶,接著獲取Channel灯谣,然后指定一個隊列直接到它關心的隊列上取消息,它對交換器蛔琅、RoutingKey及如何綁定都不關心胎许,到對應的對列上取消息就行了
名詞解釋
在該模型中,三個主要功能模塊連接成一個處理鏈完成預期的功能:
- exchange(交換器):接收發(fā)布應用程序發(fā)送的消息罗售,并根據(jù)一定的規(guī)則將這些消息路由到“消息隊列”辜窑。
- message queue(消息隊列):存儲消息,直到這些消息被消費者安全處理完為止寨躁。
- binding(綁定器):定義了exchange和message queue之間的關聯(lián)穆碎,提供路由規(guī)則。
Exchange本身不保持消息职恳,只是起到路由的作用所禀,Exchange接收消息生產(chǎn)者(MessageProducer)發(fā)送的消息根據(jù)不同的路由算法將消息發(fā)送往MessageQueue。MessageQueue會在消息不能被正常消費時緩存這些消息放钦,具體的緩存策略由實現(xiàn)者決定色徘,當MessageQueue與消息消費者(Messageconsumer)之間的連接通暢時,MessageQueue會將消息轉發(fā)到consumer操禀。
一個Broker(AMQP服務器)中會存在多個MessageQueue褂策?Exchange怎樣知道它要把消息發(fā)送到哪個MessageQueue中去呢?圖8-1中的Binding就是通過綁定Exchange與MessageQueue來解決這個問題床蜘。消息應用者(ClientApplication)控制Exchange與某個特定MessageQueue綁定辙培,并將這個MessageQueue接受何種特定消息的條件綁定到Exchange,這個條件也叫Bindingkey或Criteria邢锯。AMQP協(xié)議的架構如下圖示意扬蕊。
該圖(VirtualHost)用來指Exchange和MessageQueue組成的集合。它是一個虛擬概念丹擎,一個虛擬主機可以是一臺服務器尾抑,還可以是由多臺服務器組成的集群,還可以是一些虛擬機組成的集群蒂培,上面運行一些Exchange和MessageQueue再愈。
下面詳細解釋一下AMQP的工作原理:
從上圖看,Message是AMQP所操縱的基本單位护戳,它由Producer產(chǎn)生翎冲,經(jīng)過Broker被Consumer所消費。它的基本結構有兩部分:Header和Body媳荒。Header是由Producer添加上的各種屬性的集合抗悍,這些屬性有:控制Message是否可被緩存驹饺,接收的Queue是哪個,優(yōu)先級是多少等缴渊。Body是真正需要傳送的數(shù)據(jù)赏壹,它是對Broker不可見的二進制數(shù)據(jù)流,在傳輸過程中不應該受到影響衔沼。
一個Exchange在與多個MessageQueue通過綁定后蝌借,Exchange中就會存在一個路由表,這個表中存儲著每個MessageQueue所需要消息的限制條件指蚁。Exchange就會檢查它接收到的每個Message的Header及Body信息菩佑,來決定將Message路由到哪個Queue中去。每個Message的Header中應該有個屬性叫RoutingKey欣舵,它由Message發(fā)送者產(chǎn)生擎鸠,提供給Exchange路由這條信息的標準。Exchange根據(jù)不同路由算法有不同有ExchangeType缘圈。
- Direct類型,需要BindingKey等于RoutingKey袜蚕。也就是1對1模式糟把。
- Topic類型,所有符合RoutingKey(可以是一個表達式)RoutingKey所綁定的隊列可以接受消息牲剃。相當于通過RoutingKey進行了過濾遣疯。
- Fanout類型,忽略BindingKey和RoutingKey凿傅,消息傳遞到所有綁定的MessageQueue缠犀。即所有綁定此交換器的隊列都可以接收消息,典型的訂閱/發(fā)布模型聪舒。
- 也可以根據(jù)Message包含的某些屬性來判斷辨液。
這些基礎的路由算法由AMQP提供,當然ClientApplication也可以自定義各種自己的擴展路由算法箱残。
當Exchange按照一定的路由算法把消息發(fā)到MessageQueue后滔迈,作為消息的存儲和分發(fā)實體,MessageQueue會把消息緩存到內(nèi)存或硬盤中被辑,并且按照順序把這些消息發(fā)給一個或者多個消息的消費者燎悍。
MQ在實際項目中的使用
openStack中的MQ
OpenStack遵循這樣的設計原則:項目之間通過RESTful API進行通信;項目內(nèi)部盼理,不同服務進程之間的通信谈山,則必須要通過消息總線。這種設計思想保證了各個項目對外提供服務的接口可以被不同類型的客戶端高效支持宏怔,同時也保證了項目內(nèi)部通信接口的可擴展性和可靠性奏路,以支持大規(guī)模的部署畴椰。
軟件從最初的面向過程,面向對象思劳,再到面向服務(SOA)迅矛,要求我們?nèi)タ紤]各個服務之間如何傳遞消息。借鑒硬件總線的概念潜叛,消息總線的模式被引入秽褒,顧名思義,一些服務向總線發(fā)送消息威兜,其他服務從總線上獲取消息销斟。
OpenStack oslo.messageing庫實現(xiàn)了以下兩種方式來完成項目內(nèi)部各服務進程之間的通信:
遠程過程調(diào)用(RPC,Remote Procedure Call)
通過遠程過程調(diào)用椒舵,一個服務進程可以調(diào)用其他遠程服務進程方法蚂踊,并且有兩種調(diào)用方式:call和cast。call 則是同步執(zhí)行的笔宿,調(diào)用者會被阻塞直到結果返回犁钟;cast 則是異步執(zhí)行,結果不會立刻被返回泼橘,調(diào)用者也不會被阻塞涝动,但是調(diào)用者需要利用其他方式查詢這次遠程調(diào)用的結果。
事件通知(Event Notification)
某個服務進程可以把事件通知發(fā)送到消息總線上炬灭,該消息總線上所有對此類事件感興趣的服務進程醋粟,都可以獲得此事件通知并進行一步的處理,處理的結果并不會返回給事件發(fā)送者重归。這種通信方式米愿,不但可以在同一個項目內(nèi)部的各個服務進程之間發(fā)送通知,也可以實現(xiàn)跨項目之間的通知發(fā)送鼻吮。Ceilometer就通過這種方式大量獲取其他OpenStack項目的事件通知育苟,從而進行計量和監(jiān)控。
OpenStack中的通信方式
AMQP
OpenStack中所支持的消息總線類型中狈网,大部分都是基于AMQP的宙搬。前面已經(jīng)提到過了,故不贅述拓哺。
基于AMPQ實現(xiàn)RPC
配圖解釋:
- 客戶端發(fā)送一個請求消息給Exchange勇垛,指定routing key為"op_queue",同時指明一個消息隊列名用來獲取響應士鸥,圖中為"res_queue"闲孤。
- Exchange把此消息轉發(fā)到消息隊列op_queue
- 消息隊列op_queue把消息推送給服務端,服務端執(zhí)行此RPC調(diào)用對應的任務。執(zhí)行結束后讼积,服務端把相應結果發(fā)送給消息隊列肥照,指明routing key為"res_queue"
- Exchange 把此消息轉發(fā)到消息隊列res_queue
- 客戶端從消息隊列res_queue中獲取響應。
小結
對于MQ中的概念進行了簡單的介紹勤众。之后還會進行一定的擴充——比如在一些常見應用中MQ的應用舆绎。