天天看點

消息中間件 - RabbitMQ

RabbitMQ基礎知識

       RabbitMQ是一個由erlang開發的AMQP(Advanced Message Queue )的開源實作。AMQP 的出現其實也是應了廣大人民群衆的需求,雖然在同步消息通訊的世界裡有很多公開标準(如 COBAR的 IIOP ,或者是 SOAP 等),但是在異步消息進行中卻不是這樣,隻有大企業有一些商業實作(如微軟的 MSMQ ,IBM 的 Websphere MQ 等),是以,在 2006 年的 6 月,Cisco 、Redhat、iMatix 等聯合制定了 AMQP 的公開标準。

  RabbitMQ是由RabbitMQ Technologies Ltd開發并且提供商業支援的。該公司在2010年4月被SpringSource(VMWare的一個部門)收購。在2013年5月被并入Pivotal。其實VMWare,Pivotal和EMC本質上是一家的。不同的是VMWare是獨立上市子公司,而Pivotal是整合了EMC的某些資源,現在并沒有上市。

      講解基礎概念的前面,我們先來整體構造一個結構圖,這樣會友善們更好地去了解RabbitMQ的基本原理。

消息中間件 - RabbitMQ

圖一

   通過上面這張應用相結合的結構圖既能夠清晰的看清楚整體的send Message到Receive Message的一個大緻的流程。當然上面有很多名詞都相比還沒有介紹到,不要着急接下來我們就開始對其進行詳細的講解。

   Queue(隊列)RabbitMQ的作用是存儲消息,隊列的特性是先進先出。上圖可以清晰地看到Client A和Client B是生産者,生産者生産消息最終被送到RabbitMQ的内部對象Queue中去,而消費者則是從Queue隊列中取出資料。可以簡化成表示為:

消息中間件 - RabbitMQ

    生産者Send Message “A”被傳送到Queue中,消費者發現消息隊列Queue中有訂閱的消息,就會将這條消息A讀取出來進行一些列的業務操作。這裡隻是一個消費正對應一個隊列Queue,也可以多個消費者訂閱同一個隊列Queue,當然這裡就會将Queue裡面的消息平分給其他的消費者,但是會存在一個一個問題就是如果每個消息的處理時間不同,就會導緻某些消費者一直在忙碌中,而有的消費者處理完了消息後一直處于空閑狀态,因為前面已經提及到了Queue會平分這些消息給相應的消費者。這裡我們就可以使用prefetchCount來限制每次發送給消費者消息的個數。詳情見下圖所示:

消息中間件 - RabbitMQ

    這裡的prefetchCount=1是指每次從Queue中發送一條消息來。等消費者處理完這條消息後Queue會再發送一條消息給消費者。

    我們在開篇的時候就留了一個坑,就是那個應用結構圖裡面,消費者Client A和消費者Client B是如何知道我發送的消息是給Queue1還是給Queue2,有沒有過這個問題,那麼我們就來解開這個面紗,看看到底是個什麼構造。首先明确一點就是生産者産生的消息并不是直接發送給消息隊列Queue的,而是要經過Exchange(交換器),由Exchange再将消息路由到一個或多個Queue,當然這裡還會對不符合路由規則的消息進行丢棄掉,這裡指的是後續要談到的Exchange Type。那麼Exchange是怎樣将消息準确的推送到對應的Queue的呢?那麼這裡的功勞最大的當屬Binding,RabbitMQ是通過Binding将Exchange和Queue連結在一起,這樣Exchange就知道如何将消息準确的推送到Queue中去。簡單示意圖如下所示:

消息中間件 - RabbitMQ

     在綁定(Binding)Exchange和Queue的同時,一般會指定一個Binding Key,生産者将消息發送給Exchange的時候,一般會産生一個Routing Key,當Routing Key和Binding Key對應上的時候,消息就會發送到對應的Queue中去。那麼Exchange有四種類型,不同的類型有着不同的政策。也就是表明不同的類型将決定綁定的Queue不同,換言之就是說生産者發送了一個消息,Routing Key的規則是A,那麼生産者會将Routing Key=A的消息推送到Exchange中,這時候Exchange中會有自己的規則,對應的規則去篩選生産者發來的消息,如果能夠對應上Exchange的内部規則就将消息推送到對應的Queue中去。那麼接下來就來詳細講解下Exchange裡面類型。

    我來用表格來描述下類型以及類型之間的差別。

fanout

        fanout類型的Exchange路由規則非常簡單,它會把所有發送到該Exchange的消息路由到所有與它綁定的Queue中。

消息中間件 - RabbitMQ

    上圖所示,生産者(P)生産消息1将消息1推送到Exchange,由于Exchange Type=fanout這時候會遵循fanout的規則将消息推送到所有與它綁定Queue,也就是圖上的兩個Queue最後兩個消費者消費。

direct

        direct類型的Exchange路由規則也很簡單,它會把消息路由到那些binding key與routing key完全比對的Queue中

消息中間件 - RabbitMQ

     當生産者(P)發送消息時Rotuing key=booking時,這時候将消息傳送給Exchange,Exchange擷取到生産者發送過來消息後,會根據自身的規則進行與比對相應的Queue,這時發現Queue1和Queue2都符合,就會将消息傳送給這兩個隊列,如果我們以Rotuing key=create和Rotuing key=confirm發送消息時,這時消息隻會被推送到Queue2隊列中,其他Routing Key的消息将會被丢棄。

topic

      前面提到的direct規則是嚴格意義上的比對,換言之Routing Key必須與Binding Key相比對的時候才将消息傳送給Queue,那麼topic這個規則就是模糊比對,可以通過通配符滿足一部分規則就可以傳送。它的約定是:

routing key為一個句點号“. ”分隔的字元串(我們将被句點号“. ”分隔開的每一段獨立的字元串稱為一個單詞),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”

binding key與routing key一樣也是句點号“. ”分隔的字元串

binding key中可以存在兩種特殊字元“*”與“#”,用于做模糊比對,其中“*”用于比對一個單詞,“#”用于比對多個單詞(可以是零個)

消息中間件 - RabbitMQ

  當生産者發送消息Routing Key=F.C.E的時候,這時候隻滿足Queue1,是以會被路由到Queue中,如果Routing Key=A.C.E這時候會被同是路由到Queue1和Queue2中,如果Routing Key=A.F.B時,這裡隻會發送一條消息到Queue2中。

headers

headers類型的Exchange不依賴于routing key與binding key的比對規則來路由消息,而是根據發送的消息内容中的headers屬性進行比對。

在綁定Queue與Exchange時指定一組鍵值對;當消息發送到Exchange時,RabbitMQ會取到該消息的headers(也是一個鍵值對的形式),對比其中的鍵值對是否完全比對Queue與Exchange綁定時指定的鍵值對;如果完全比對則消息會路由到該Queue,否則不會路由到該Queue。

該類型的Exchange沒有用到過(不過也應該很有用武之地),是以不做介紹。

這裡在對其進行簡要的表格整理:

Exchange規則

<col>

類型名稱

類型描述

把所有發送到該Exchange的消息路由到所有與它綁定的Queue中

Routing Key==Binding Key

我這裡自己總結的簡稱模糊比對

Exchange不依賴于routing key與binding key的比對規則來路由消息,而是根據發送的消息内容中的headers屬性進行比對。

  ConnectionFactory、Connection、Channel都是RabbitMQ對外提供的API中最基本的對象。Connection是RabbitMQ的socket連結,它封裝了socket協定相關部分邏輯。ConnectionFactory為Connection的制造工廠。

  Channel是我們與RabbitMQ打交道的最重要的一個接口,我們大部分的業務操作是在Channel這個接口中完成的,包括定義Queue、定義Exchange、綁定Queue與Exchange、釋出消息等。

  Connection就是建立一個TCP連接配接,生産者和消費者的都是通過TCP的連接配接到RabbitMQ Server中的,這個後續會再程式中展現出來。

  Channel虛拟連接配接,建立在上面TCP連接配接的基礎上,資料流動都是通過Channel來進行的。為什麼不是直接建立在TCP的基礎上進行資料流動呢?如果建立在TCP的基礎上進行資料流動,建立和關閉TCP連接配接有代價。頻繁的建立關閉TCP連接配接對于系統的性能有很大的影響,而且TCP的連接配接數也有限制,這也限制了系統處理高并發的能力。但是,在TCP連接配接中建立Channel是沒有上述代價的。

三、結束語

相信學過這篇文章的人都會對RabbitMQ有一個初步的了解。本篇文章是建立在上面兩篇文章的基礎上加上自己的了解而形成的,收獲很多。其實我個人感覺寫一篇文章并不容易,因為要查很多資料以及想很多面,要嚴謹不能說寫出來的東西沒有通過驗證就發出來這樣給别人帶來了誤導,那我覺得是我的損失。是以如果又看了文章說那些又錯誤了就請指正,小丁會将它改過來。