標籤:activemq 架構 rabbitmq 通訊 訊息中介軟體
柯南君上一章《柯南君:看大資料時代下的IT架構(1)業界訊息佇列對比 》中,粗略的講了一下,目前訊息佇列的幾種常見產品的優劣對比,接下來的幾章節會分別詳細闡述,本章介紹RabbitMQ,好吧,廢話少說,正式開始:
一、基礎概念詳細介紹1、引言
你是否遇到過兩個(多個)系統間需要通過定時任務來同步某些資料?你是否在為異構系統的不同進程間相互調用、通訊的問題而苦惱、掙紮?如果是,那麼恭喜你,Message Service讓你可以很輕鬆地解決這些問題。
Message Service擅長於解決多系統、異構系統間的資料交換(訊息通知/通訊)問題,你也可以把它用於系統間服務的相互調用(RPC)。本文將要介紹的RabbitMQ就是當前最主流的訊息中介軟體之一。
2、RabbitMQ簡介
RabbitMQ是流行的開源訊息佇列系統,用erlang語言開發。RabbitMQ是AMQP(進階訊息佇列協議)的標準實現。如果不熟悉AMQP,直接看RabbitMQ的文檔會比較困難。首先講一下
AMQP
AMQP,即Advanced Message Queuing Protocol,進階訊息佇列協議,是應用程式層協議的一個開放標準,為面向訊息的中介軟體設計。訊息中介軟體主要用於組件之間的解耦,訊息的寄件者無需知道訊息使用者的存在,反之亦然。
AMQP的主要特徵是面向訊息、隊列、路由(包括點對點和發布/訂閱)、可靠性、安全。
RabbitMQ是一個開源的AMQP實現,伺服器端用Erlang語言編寫,支援多種用戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支援AJAX。用於在分布式系統中儲存轉寄訊息,在易用性、擴充性、高可用性等方面表現不俗。
下面將重點介紹RabbitMQ中的一些基礎概念,瞭解了這些概念,是使用好RabbitMQ的基礎。3、基本概念1)RabbitMQ 結構圖如下:2)重點介紹一些比較重要基礎概念
① Query :(隊列)Query(隊列)是RabbitMQ的內部對象,用於儲存資訊,有(1-3-2-1)表示
(
1-3-2-1)RabbitMQ中的資訊只能儲存在Query中,生產者(中的P)生產者訊息並最終投遞到Query中,消費者(中1-3-2-2的C)可以從Query中擷取訊息並消費。(
1-3-2-2)多個消費者可以訂閱同一個Query,這時Query中的訊息會被平均分攤給多個消費者進行處理,而不是每個消費者都收到所有訊息並處理。
②
Message acknowlegment:(訊息回執)在實際應用中,可能會發生消費者收到Query中的訊息,但沒有處理完成就宕機的情況,這種情況下,就可能導致資訊丟失,為了避免這種情況發生,我們可以要求消費者在消費完訊息後發送一個回執給RabbitMQ,RabbitMQ收到訊息回執(Message acknowledge)後,才將該訊息從Query中移除。如果RabbitMQ沒有收到回執,並檢測到消費者的RabbitMQ連結斷開,則RabbitMQ 會將該訊息發送給其他消費者(如果存在多個消費者的情況下)進行處理,這裡不存在timeout的概念,一個消費者處理消費時間不管多麼長也不會導致該訊息被發送給其他消費者,除非它的RabbitMQ串連斷開;
注意:這裡會產生一個問題,如果開發人員再處理業務完成邏輯後,忘記發送回執給RabbitMQ,這將會導致嚴重的bug---Query中堆積的訊息會越來越多;消費者重啟會重複消費這些訊息並重複執行商務邏輯。
③Message durability:(訊息持久化)如果我們希望即使在RabbitMQ在重啟的情況下,也不會丟失訊息,那麼我們將Query與Message都設定成可持久化的(durability),這樣就可以保證絕大部分情況下我們的RabbitMQ訊息不會丟失。但依然解決不了小機率的丟失事件的發生(
比如 RabbitMQ伺服器已經接收到生產者的訊息,但是,還沒有來的及持久化該訊息時,RabbitMQ伺服器就斷電了或者宕機了),如果我們需要對這種小機率事件也要管理起來的話,那麼我們需要用到事務。
④ Prefetch count (預取數目)前面我們提到了如果有多個消費者同時訂閱同一個Query中的訊息,Query中的訊息會被平攤給多個消費者。這時如果每個訊息的處理時間不同,就有可能導致某些消費者一直很忙,而另一些消費者很快處理完手頭上工作,並一直閒置情況下。我們可以通過設定prefetch count=1,則Query每次給每個消費者發送一條訊息;消費者處理完這條訊息後Query會再給消費者發送一條訊息。⑤
Exchange (交換器)
上一節我們看到生產者將訊息投遞到Query中,實際上這在RabbitMQ是不可能發生的,實際上的情況是,生產者將訊息發送到Exchange(交換器,中X),Exchange將訊息路由到一個或者多個Query中或者丟棄。Exchange是按照什麼邏輯將訊息路由到Query的?這將在Binding一節詳談。RabbitMQ中的Exchange有四種類型,不同的類型有著不同的路由策略,這將在Exchange Types一節詳談
⑥ routing key(路由key)生產者在將訊息發送給Exchange的時候,一般會指定一個routing key,來指定這個路由規則,而這個routing key需要與 Exchange Type 與binding key 聯合使用才能最終生效。在Exchange Tpye 與binding key 固定的情況下(在正常使用方式下,這些內容都是配置好的),我們的生產者就可以在發送訊息給Exchange的時候,通過指定routing key 來指定訊息流程的流向哪裡。⑦
Binding (綁定)RabbitMQ 中通過Binding 將Exchange 與Query關聯起來,這樣RabbitMQ就知道如何正確地將訊息路由到指定的Query了⑧ Exchange Type (更換類型)RabbitMQ常用的Exchange Tpye 有fanout、direct、top、headers這四種⑨ fanout (分列)fanout類型的Exchange路由規則非常簡單,它會把所有發送到該Exchange的訊息路由到所有與它綁定的Queue中。
⑩ direct (重新導向)direct類型的Exchange路由規則也很簡單,它會把訊息路由到那些binding key與routing key完全符合的Queue中。
以的配置為例,我們以routingKey=”error”發送訊息到Exchange,則訊息會路由到Queue1(amqp.gen-S9b…,這是由RabbitMQ自動產生的Queue名稱)和Queue2(amqp.gen-Agl…);如果我們以routingKey=”info”或routingKey=”warning”來發送訊息,則訊息只會路由到Queue2。如果我們以其他routingKey發送訊息,則訊息不會路由到這兩個Queue中。? topic(主題)
前面講到direct類型的Exchange路由規則是完全符合binding key與routing key,但這種嚴格的匹配方式在很多情況下不能滿足實際業務需求。topic類型的Exchange在匹配規則上進行了擴充,它與direct類型的Exchage相似,也是將訊息路由到binding key與routing key相匹配的Queue中,但這裡的匹配規則有些不同,它約定:
- routing key為一個句點號“. ”分隔的字串(我們將被句點號“. ”分隔開的每一段獨立的字串稱為一個單詞),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
- binding key與routing key一樣也是句點號“. ”分隔的字串
- binding key中可以存在兩種特殊字元“*”與“#”,用於做模糊比對,其中“*”用於匹配一個單詞,“#”用於匹配多個單詞(可以是零個)】
以中的配置為例,routingKey=”quick.orange.rabbit”的訊息會同時路由到Q1與Q2,routingKey=”lazy.orange.fox”的訊息會路由到Q1,routingKey=”lazy.brown.fox”的訊息會路由到Q2,routingKey=”lazy.pink.rabbit”的訊息會路由到Q2(只會投遞給Q2一次,雖然這個routingKey與Q2的兩個bindingKey都匹配);routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的訊息將會被丟棄,因為它們沒有匹配任何bindingKey。? headersheaders類型的Exchange不依賴於routing key與binding key的匹配規則來路由訊息,而是根據發送的訊息內容中的headers屬性進行匹配。
在綁定Queue與Exchange時指定一組鍵值對;當訊息發送到Exchange時,RabbitMQ會取到該訊息的headers(也是一個鍵值對的形式),對比其中的鍵值對是否完全符合Queue與Exchange綁定時指定的鍵值對;如果完全符合則訊息會路由到該Queue,否則不會路由到該Queue。
該類型的Exchange沒有用到過(不過也應該很有用武之地),所以不做介紹。? RPC(遠端程序呼叫)MQ本身是基於非同步訊息處理,前面的樣本中所有的生產者(P)將訊息發送到RabbitMQ後不會知道消費者(C)處理成功或者失敗(甚至連有沒有消費者來處理這條訊息都不知道)。
但實際的應用情境中,我們很可能需要一些同步處理,需要同步等待服務端將我的訊息處理完成後再進行下一步處理。這相當於RPC(Remote Procedure Call,遠端程序呼叫)。在RabbitMQ中也支援RPC。
RabbitMQ中實現RPC的機制是:
- 用戶端發送請求(訊息)時,在訊息的屬性(MessageProperties,在AMQP協議中定義了14中properties,這些屬性會隨著訊息一起發送)中設定兩個值replyTo(一個Queue名稱,用於告訴伺服器處理完成後將通知我的訊息發送到這個Queue中)和correlationId(此次請求的標識號,伺服器處理完成後需要將此屬性返還,用戶端將根據這個id瞭解哪條請求被成功執行了或執行失敗)
- 伺服器端收到訊息並處理
- 伺服器端處理完訊息後,將產生一條應答訊息到replyTo指定的Queue,同時帶上correlationId屬性
- 用戶端之前已訂閱replyTo指定的Queue,從中收到伺服器的應答訊息後,根據其中的correlationId屬性分析哪條請求被執行了,根據執行結果進行後續業務處理
二、MQ特點三、使用情境四、含義五、安裝http://blog.csdn.net/sun305355024sun/article/details/41918315六、用戶端七、服務端
柯南君:看大資料時代下的IT架構(2)訊息佇列之RabbitMQ-基礎概念詳細介紹