RabbitMQ消息隊列(五):Routing 消息路由[轉]

上篇文章中,我們構建了一個簡單的日誌系統。接下來,我們將豐富它:能夠使用不同的severity(嚴重程度)來監聽不同等級的log。比如我們希望只有error的log才保存到磁盤上。

1. Bindings綁定

    上篇文章中我們是這麼做的綁定:

channel.QueueBind(queueName, EXCHANGE_NAME, ROUTING_KEY);//const string ROUTING_KEY = "";

    綁定其實就是關聯了exchange和queue。或者這麼說:queue對exchange的內容感興趣,exchange要把它的Message deliver(提供)到queue中。

    實際上,綁定可以帶routing key這個參數,空字符串也是一個routing key的名字。其實這個參數的名稱和basic_publish的參數名是相同了。第二篇有介紹當exchange的名稱爲空字符串的時候,創建queue的時候用到queue的名字和Producer的BasicPublish方法或Consuner的BasicConsume方法的routing key的名字可以是相同的。即queue的名字和routing key的名字是相同的。

   爲了避免混淆,我們把這個routing key稱爲binding key(即在Exchange中的routing key)

    使用一個binding key來創建binding :

channel.QueueBind(queueName, EXCHANGE_NAME, routingKey);//string routingKey = "指定RoutingKey的名稱";

上一篇文章我們講的是使用fanout類型的exchange,對於fanout的exchange來說,這個參數是被忽略的。

2. Direct exchange

  Direct exchange的路由算法非常簡單:通過binding key的完全匹配,可以通過下圖來說明。


    exchange X和兩個queue綁定在一起。Q1的binding key是orange。Q2的binding key是black和green。
    當P發佈的key是orange時,exchange會把它放到Q1。如果P發佈的key是black或者green那麼就會到Q2。其餘的Message都會被丟棄。本篇最後面(queue的名字是rabbitmq自己起的)和下一篇第一個例子(queue的名字是程序指定的)就是實現這上面這副圖的代碼——將多個routing key(或者稱爲binding key)綁定到同一個名稱的queue。

3. Multiple bindings

      多個queue綁定同一個key是可以的。對於下圖的例子,Q1和Q2都綁定了black。也就是說,對於routing key是black的Message,會被deliver(提供)到Q1和Q2。其餘的Message都會被丟棄。下一篇第二個例子就是講這副圖的例子,將同一個routing key(或者binding key)綁定到多個不同名稱的queue上。
 
 

4. Emitting logs

首先是我們要創建一個direct的exchange:

const string EXCHANGE_NAME = "direct_logs";
channel.ExchangeDeclare(EXCHANGE_NAME, "direct");

我們將使用log的severity(嚴重級別)作爲routing key,這樣Consumer可以針對不同severity(嚴重級別)的log進行不同的處理。

channel.BasicPublish(EXCHANGE_NAME, routingKey, null, body);

我們使用三種severity(嚴重級別):'info', 'warning', 'error'.

5. Subscribing

對於queue,我們需要綁定severity(嚴重級別):

const string EXCHANGE_NAME = "direct_logs";
channel.ExchangeDeclare(EXCHANGE_NAME, "direct");
string queueName = channel.QueueDeclare();

channel.QueueBind(queueName, EXCHANGE_NAME, routingKey);

6. 最終版本

本例子是沒有指定Queue的名稱:
Producer.cs
複製代碼
 1  /// <summary>
 2         /// 多個routing key指定同一個queue
 3         /// 接收端創建臨時queue
 4         /// </summary>
 5         /// <param name="args">
 6         /// SendDemo5.exe direct_custom_routing_key_hello1
 7         /// SendDemo5.exe direct_custom_routing_key_hello2
 8         /// </param>
 9         static void Main(string[] args)
10         {
11             if (args.Length < 1)
12             {
13                 Console.Error.WriteLine("請指定一個新的Routing Key名稱", Environment.GetCommandLineArgs()[0]);
14                 Environment.ExitCode = 1;
15                 return;
16             }
17             var factory = new ConnectionFactory() { HostName = "localhost" };
18             using (var connection = factory.CreateConnection())
19             {
20                 using (var channel = connection.CreateModel())
21                 {
22                     const string EXCHANGE_NAME = "direct_logs";
23                     channel.ExchangeDeclare(EXCHANGE_NAME, "direct");//Direct :如果 routing key 匹配, 那麼Message就會被傳遞到相應的queue中。
24                     //Exchange在queue創建時,它會自動的以queue的名字作爲routing key來綁定那個exchange。
25                     var routingKey = args[0];
26                     var message = "Hello World!";
27                     var body = Encoding.UTF8.GetBytes(message);
28                     
29                     channel.BasicPublish(EXCHANGE_NAME, routingKey, null, body);
30                     Console.WriteLine(" [x] Sent '{0}':'{1}'", routingKey, message);
31                 }
32             }
33         }
複製代碼

Consumer.cs

複製代碼
 1 /// <summary>
 2         /// 多個routing key指定同一個queue
 3         /// 接收端創建臨時queue
 4         /// </summary>
 5         /// <param name="args">
 6         /// ReceiveDemo5.exe direct_custom_routing_key_hello1
 7         /// ReceiveDemo5.exe direct_custom_routing_key_hello2
 8         /// </param>
 9         static void Main(string[] args)
10         {
11             if (args.Length < 1)
12             {
13                 Console.Error.WriteLine("請指定一個新的Routing Key名稱", Environment.GetCommandLineArgs()[0]);
14                 Environment.ExitCode = 1;
15                 return;
16             }
17             var factory = new ConnectionFactory() { HostName = "localhost" };
18             using (var connection = factory.CreateConnection())
19             {
20                 using (var channel = connection.CreateModel())
21                 {
22                     const string EXCHANGE_NAME = "direct_logs";
23                     channel.ExchangeDeclare(EXCHANGE_NAME, "direct");//接收端如果關閉之後,自動創建的Queue會自動被刪除
24                     string queueName = channel.QueueDeclare();//獲取臨時創建的Queue的名稱
25                    
26                     foreach (var routingKey in args)
27                     {
28                         channel.QueueBind(queueName, EXCHANGE_NAME, routingKey);
29                     }
30 
31                     Console.WriteLine(" [*] Waiting for messages. " + "To exit press CTRL+C");
32 
33                     var consumer = new QueueingBasicConsumer(channel);
34                     channel.BasicConsume(queueName, true, consumer);
35 
36                     while (true)
37                     {
38                         var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
39 
40                         var body = ea.Body;
41                         var message = Encoding.UTF8.GetString(body);
42                         var routingKey = ea.RoutingKey;
43                         Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message);
44                     }
45                 }
46             }
47         }
複製代碼

必須先運行Consumer,然後在運行Producer.

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