在 Windows 上安裝Rabbit MQ 指南

rabbitMQ是一個在AMQP協議標準基礎上完整的,可服用的企業消息系統。他遵循Mozilla Public License開源協議。採用 Erlang 實現的工業級的消息隊列(MQ)服務器。

     RabbitMQ的官方站:http://www.rabbitmq.com/
       AMQP(高級消息隊列協議) 是一個異步消息傳遞所使用的應用層協議規範,作爲線路層協議,而不是API(例如JMS),AMQP 客戶端能夠無視消息的來源任意發送和接受信息。AMQP的原始用途只是爲金融界提供一個可以彼此協作的消息協議,而現在的目標則是爲通用消息隊列架構提供通用構建工具。因此,面向消息的中間件 (MOM)系統,例如發佈/訂閱隊列,沒有作爲基本元素實現。反而通過發送簡化的AMQ實體,用戶被賦予了構建例如這些實體的能力。這些實體也是規範的一 部分,形成了在線路層協議頂端的一個層級:AMQP模型。這個模型統一了消息模式,諸如之前提到的發佈/訂閱,隊列,事務以及流數據,並且添加了額外的特性,例如更易於擴展,基於內容的路由。

AMQP當中有四個概念非常重要

  1. virtual host,虛擬主機
  2. exchange,交換機
  3. queue,隊列
  4. binding,綁定

一個虛擬主機持有一組交換機、隊列和綁定。

爲什麼需要多個虛擬主機呢?因爲RabbitMQ當中,用戶只能在虛擬主機的粒度進行權限控制。因此,如果需要禁止A組訪問B組的交換機/隊列/綁定,必須爲A和B分別創建一個虛擬主機。每一個RabbitMQ服務器都有一個默認的虛擬主機/

何謂虛擬主機(virtual host),交換機(exchange),隊列(queue)和綁定(binding)

隊列(Queues)是你的消息(messages)的終點,可以理解成裝消息的容器。消息就一直在裏面,直到有客戶端(也就是消費者,Consumer)連接到這個隊列並且將其取走爲止。不過,也可以將一個隊列配置成這樣的:一旦消息進入這個隊列,此消息就被刪除。

隊列是由消費者(Consumer)通過程序建立的,不是通過配置文件或者命令行工具。這沒什麼問題,如果一個消費者試圖創建一個已經存在的隊列,RabbitMQ會直接忽略這個請求。因此我們可以將消息隊列的配置寫在應用程序的代碼裏面。

而要把一個消息放進隊列前,需要有一個交換機(Exchange)。

交換機(Exchange)可以理解成具有路由表的路由程序。每個消息都有一個稱爲路由鍵(routing key)的屬性,就是一個簡單的字符串。交換機當中有一系列的綁定(binding),即路由規則(routes)。(例如,指明具有路由鍵 “X” 的消息要到名爲timbuku的隊列當中去。)

消費者程序(Consumer)要負責創建你的交換機。交換機可以存在多個,每個交換機在自己獨立的進程當中執行,因此增加多個交換機就是增加多個進程,可以充分利用服務器上的CPU核以便達到更高的效率。例如,在一個8核的服務器上,可以創建5個交換機來用5個核,另外3個核留下來做消息處理。類似的,在RabbitMQ的集羣當中,你可以用類似的思路來擴展交換機一邊獲取更高的吞吐量。

交換機如何判斷要把消息送到哪個隊列?你需要路由規則,即綁定(binding)。一個綁定就是一個類似這樣的規則:將交換機“desert(沙漠)”當中具有路由鍵“阿里巴巴”的消息送到隊列“hideout(山洞)”裏面去。換句話說,一個綁定就是一個基於路由鍵將交換機和隊列連接起來的路由規則。例如,具有路由鍵“audit”的消息需要被送到兩個隊列,“log-forever”和“alert-the-big-dude”。要做到這個,就需要創建兩個綁定,每個都連接一個交換機和一個隊列,兩者都是由“audit”路由鍵觸發。在這種情況下,交換機會複製一份消息並且把它們分別發送到兩個隊列當中。交換機不過就是一個由綁定構成的路由表。

交換機有多種類型。他們都是做路由的,但是它們接受不同類型的綁定。爲什麼不創建一種交換機來處理所有類型的路由規則呢?因爲每種規則用來做匹配分子的CPU開銷是不同的。例如,一個“topic”類型的交換機試圖將消息的路由鍵與類似“dogs.*”的模式進行匹配。匹配這種末端的通配符比直接將路由鍵與“dogs”比較(“direct”類型的交換機)要消耗更多的CPU。如果你不需要“topic”類型的交換機帶來的靈活性,你可以通過使用“direct”類型的交換機獲取更高的處理效率。那麼有哪些類型,他們又是怎麼處理的呢?

  Exchange


  1. Exchange Direct


    Exchange Fanout


Exchange Topic



持久化

你花了大量的時間來創建隊列、交換機和綁定,然後,服務器程序掛了。你的隊列、交換機和綁定怎麼樣了?還有,放在隊列裏面但是尚未處理的消息們呢?

如果你是用默認參數構造的這一切的話,那麼,他們都灰飛煙滅了。RabbitMQ重啓之後會乾淨的像個新生兒。你必須重做所有的一切,亡羊補牢,如何避免將來再度發生此類杯具?

隊列和交換機有一個創建時候指定的標誌durable。durable的唯一含義就是具有這個標誌的隊列和交換機會在重啓之後重新建立,它不表示說在隊列當中的消息會在重啓後恢復。那麼如何才能做到不只是隊列和交換機,還有消息都是持久的呢?

但是首先需要考慮的問題是:是否真的需要消息的持久化?如果需要重啓後消息可以回覆,那麼它需要被寫入磁盤。但即使是最簡單的磁盤操作也是要消耗時間的。所以需要衡量判斷。

當你將消息發佈到交換機的時候,可以指定一個標誌“Delivery Mode”(投遞模式)。根據你使用的AMQP的庫不同,指定這個標誌的方法可能不太一樣。簡單的說,就是將Delivery Mode設置成2,也就是持久的(persistent)即可。一般的AMQP庫都是將Delivery Mode設置成1,也就是非持久的。所以要持久化消息的步驟如下:

  1. 將交換機設成 durable。
  2. 將隊列設成 durable。
  3. 將消息的 Delivery Mode 設置成2 。

綁定(Bindings)怎麼辦?綁定無法在創建的時候設置成durable。沒問題,如果你綁定了一個durable的隊列和一個durable的交換機,RabbitMQ會自動保留這個綁定。類似的,如果刪除了某個隊列或交換機(無論是不是durable),依賴它的綁定都會自動刪除。

注意:

  • RabbitMQ 不允許你綁定一個非堅固(non-durable)的交換機和一個durable的隊列。反之亦然。要想成功必須隊列和交換機都是durable的。
  • 一旦創建了隊列和交換機,就不能修改其標誌了。例如,如果創建了一個non-durable的隊列,然後想把它改變成durable的,唯一的辦法就是刪除這個隊列然後重現創建。因此,最好仔細檢查創建的標誌。

在Windows上安裝Rabbit MQ 指南,最好的是這篇《Rabbit MQ Windows Installation guide》,其中還包括了使用.NET RabbitMQ.Client Nuget 包訪問Rabbit MQ的示例代碼。

安裝Rabbit MQ

Rabbit MQ 是建立在強大的Erlang OTP平臺上,因此安裝Rabbit MQ的前提是安裝Erlang。通過下面兩個連接下載安裝3.2.3 版本:

  1. 下載並安裝 Eralng OTP For Windows (vR16B03)
  2. 運行安裝 Rabbit MQ Server Windows Installer (v3.2.3)

默認安裝的Rabbit MQ 監聽端口是5672

激活Rabbit MQ's Management Plugin

使用Rabbit MQ 管理插件,可以更好的可視化方式查看Rabbit MQ 服務器實例的狀態,你可以在命令行中使用下面的命令激活:

"C:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin\rabbitmq-plugins.bat" enable rabbitmq_management

要重啓服務才能生效,可以執行

net stop RabbitMQ && net start RabbitMQ

下面我們使用rabbitmqctl控制檯命令(位於C:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>)來創建用戶,密碼,綁定權限等。

Microsoft Windows [版本 6.3.9600]
(c) 2013 Microsoft Corporation。保留所有權利。

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin 的目錄

2014/11/01  15:04    <DIR>          .
2014/11/01  15:04    <DIR>          ..
2014/01/23  22:57               817 rabbitmq-echopid.bat
2014/01/23  22:57             1,900 rabbitmq-plugins.bat
2014/01/23  22:57             4,356 rabbitmq-server.bat
2014/01/23  22:57             7,123 rabbitmq-service.bat
2014/01/23  22:57             1,621 rabbitmqctl.bat
               5 個文件         15,817 字節
               2 個目錄 96,078,618,624 可用字節

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>rabbitmqctl.ba
t list_users
Listing users ...
guest   [administrator]
...done.

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>rabbitmqctl.ba
t list_vhosts
Listing vhosts ...
/
...done.

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>rabbitmqctl.ba
t add_user geffzhang zsy@2014
Creating user "geffzhang" ...
...done.

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>rabbitmqctl.ba
t list_users
Listing users ...
geffzhang       []
guest   [administrator]
...done.

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>rabbitmqctl.ba
t set_user_tags geffzhang administrator
Setting tags for user "geffzhang" to [administrator] ...
...done.

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>rabbitmqctl.ba
t set_permissions -p /  geffzhang ".*" ".*" ".*"
Setting permissions for user "geffzhang" in vhost "/" ...
...done.

c:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.2.3\sbin>rabbitmqctl.ba
t list_users
Listing users ...
geffzhang       [administrator]
guest   [administrator]
...done.

使用瀏覽器打開http://localhost:15672 訪問Rabbit Mq的管理控制檯,使用剛纔創建的賬號登陸系統:

image

在.NET上使用Rabbit MQ

通過Nuget 獲取Rabbit MQ NET client bindings from NuGet:

PM> Install-Package RabbitMQ.Client

我們最常見的一個場景是發送和接收Rabbit MQ 持久化消息:

第一步是聲明durable Exchange 和 Queue

 private readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory { HostName = "Geffzhang-NB", UserName="geffzhang", Password ="zsy@2014", VirtualHost ="/" };
const string ExchangeName="test.exchange";
const string QueueName = "test.queue";

using (IConnection conn = rabbitMqFactory.CreateConnection())
using (IModel channel=conn.CreateModel())
{
    channel.ExchangeDeclare(ExchangeName,"direct",durable:true,autoDelete:false,arguments:null);

    channel.QueueDeclare(QueueName,durable:true,exclusive:false, autoDelete:false,arguments:null);
    channel.QueueBind(QueueName,ExchangeName,routingKey:QueueName);
}

下面對上面代碼進行說明:
1.  使用ConnectionFactory創建連接,雖然創建時指定了多個server address,但每個connection只與一個物理的server進行連接。

2.  定義交換方式 ,創建了Direct Exchange和Durable Queue,並使用QueueName作爲routing key ,可以把消息直接投遞到某個隊列。rabbitmq交換方式分爲三種,分別是:
        Direct Exchange – 處理路由鍵。需要將一個隊列綁定到交換機上,要求該消息與一個特定的路由鍵完全匹配。這是一個完整的匹配。如果一個隊列綁定到該交換機上要求路由鍵 “dog”,則只有被標記爲“dog”的消息才被轉發,不會轉發dog.puppy,也不會轉發dog.guard,只會轉發dog。
        Fanout Exchange – 不處理路由鍵。你只需要簡單的將隊列綁定到交換機上。一個發送到交換機的消息都會被轉發到與該交換機綁定的所有隊列上。很像子網廣播,每臺子網內的主機都獲得了一份複製的消息。Fanout交換機轉發消息是最快的。
        Topic Exchange – 將路由鍵和某模式進行匹配。此時隊列需要綁定要一個模式上。符號“#”匹配一個或多個詞,符號“*”匹配不多不少一個詞。因此“audit.#”能夠匹配到“audit.irs.corporate”,但是“audit.*” 只會匹配到“audit.irs”。

運行上述代碼,可以在Rabbit MQ的管理控制檯上看到test.exchange Exchange 綁定到 創建的隊列test.queue

第二步就是發佈持久化消息到隊列

Exchange和Queue建立好以後,就可以發送消息到隊列了。RabbitMq 可以接受byte[]的數據,字符串採用utf-8編碼的字節數組。確保消息可持久化的,需要設置PersistMode爲true,參看下面的代碼:

var props = channel.CreateBasicProperties();
props.SetPersistent(true);

var msgBody = Encoding.UTF8.GetBytes("Hello, World!");
channel.BasicPublish(ExchangeName,routingKey:QueueName,basicProperties:props,body:msgBody);
第三步就是消費消息了,有幾種不同的方法從隊列中消費消息,最常見的是使用BasicGet

BasicGetResult msgResponse = channel.BasicGet(QueueName, noAck: true);

var msgBody = Encoding.UTF8.GetString(msgResponse.Body);

NoAck:true 告訴RabbitMQ立即從隊列中刪除消息,另一個非常受歡迎的方式是從隊列中刪除已經確認接收的消息,可以通過單獨調用BasicAck 進行確認:

BasicGetResult msgResponse = channel.BasicGet(QueueName,noAck:false);

//process message ...

channel.BasicAck(msgResponse.DeliveryTag,multiple:false);
使用BasicAck方式來告之是否從隊列中移除該條消息,這一點很重要,因爲在某些應用場景下,比如從隊列中獲取消息並用它來操作數據庫或日誌文件時,如果出現操作失敗時,則該條消息應該保留在隊列中,只到操作成功時才從隊列中移除。

種方法通過基於推送事件訂閱可以使用內置QueueingBasicConsumer提供簡化編程模型通過允許共享隊列阻塞直到收到條消息例如

var consumer = new QueueingBasicConsumer(channel);    

channel.BasicConsume(QueueName, noAck: true, consumer: consumer);

var msgResponse = consumer.Queue.Dequeue(); //blocking

var msgBody = Encoding.UTF8.GetString(msgResponse.Body);


引用文獻: http://www.cnblogs.com/shanyou/p/4067250.html


如何基於RabbitMQ實現優先級隊列

https://github.com/derekgreer/rabbitBus

https://github.com/evolvIQ/PushMQ


rabbitmq 官方網站: 

http://www.rabbitmq.com/install-windows.html




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