RabbitMQ 入門系列:8、擴展內容:接收資訊時:可否根據RoutingKey過濾監聽資訊,答案是不能。
系列目錄
前言:
初看交換機的概念時,以為會有根據綁定的RoutingKey進行過濾監聽的功能。
而網上,也有一些誤導人程式碼,連我也被誤了不少時間。
答案已經在標題上有了,下面看一些錯誤的演示。
1、網上離譜的標準錯誤答案:DotNet版本
1、發送方:
ConnectionFactory factory = new ConnectionFactory()
{
HostName = "127.0.0.1",
UserName = "guest",
Password = "guest",
VirtualHost = "/"
};
string myexchange = "myexchange";string myqueue = "myqueue";
using (var connection = factory.CreateConnection())
{
var channel = connection.CreateModel();
channel.ExchangeDeclare(myexchange, ExchangeType.Direct, true, false, null);
channel.QueueDeclare(myqueue, true, false, false, null);
channel.QueueBind(myqueue, myexchange, "log_info", null);
channel.QueueBind(myqueue, myexchange, "log_error", null);
for (int i = 0; i < 10; i++)
{
var msg = Encoding.UTF8.GetBytes($"{i},你好");
var routeKey = i % 2 == 0 ? "log_info" : "log_error";
channel.BasicPublish(myexchange, routingKey: routeKey, basicProperties: null, body: msg);
}
}
向隊列myqueue發送了10條數據:

可以看到,隊列消息里是帶有Routing Key。
然後以為可以只監聽獲取對應的Routing Key的數據,這種錯誤認知就被帶出了,還演示了無效的程式碼:
2、接收方:
ConnectionFactory factory = new ConnectionFactory()
{
HostName = "127.0.0.1",
UserName = "guest",
Password = "guest",
VirtualHost = "/"
};
string myexchange = "myexchange";
string myqueue = "myqueue";
using (var connection = factory.CreateConnection())
{
var channel = connection.CreateModel();
channel.QueueBind(myqueue, myexchange, "log_info", null);
EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, e) =>
{
var msg = Encoding.UTF8.GetString(e.Body);
Console.WriteLine(msg + " Routing Key :" + e.RoutingKey);
};
channel.BasicConsume(myqueue, false, consumer);
Console.ReadKey();
}
天真以為綁定對應路由器就有效,運行結果仍是:

真實的答案就只有一個:它是隊列,不是資料庫,無法根據條件過濾過查詢。
2、網上容易誤導的進階式標準錯誤答案2:來源參考的是Java版本
發送方保持不變,修改接收方的程式碼:
ConnectionFactory factory = new ConnectionFactory()
{
HostName = "127.0.0.1",
UserName = "guest",
Password = "guest",
VirtualHost = "/"
};
string myexchange = "myexchange";
using (var connection = factory.CreateConnection())
{
var channel = connection.CreateModel();
string name = channel.QueueDeclare().QueueName;
channel.QueueBind(name, myexchange, "log_info", null);
EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, e) =>
{
var msg = Encoding.UTF8.GetString(e.Body);
Console.WriteLine(msg + " Routing Key :" + e.RoutingKey);
};
channel.BasicConsume(name, false, consumer);
Console.ReadKey();
}
重新定義臨時隊列,然後綁定了臨時隊列的名稱,開啟監聽,然後讓發送方再次發送數據:

右邊發送了10條,左邊根據過濾條件,收到了5條,看起來好像達到效果了。
表現上很正確,這就很TMD的誤導人了。
下面看看這種是什麼情況:

實際的情況是:
1、接收方:創建了臨時隊列,同時綁定log_info,監聽的是臨時隊列。
2、發送方:即發送到myqueue,對log_info的數據,再copy一份發送到臨時隊列。
這就很離譜了,會造成以下幾個問題:
1、只能收到監聽開啟之後發送的數據,對myqueue之前的數據是獲取不到的。
也即是說,僅有雙方同時在線,發送時的數據才能收到,其餘條件的數據都會丟失。
2、myqueue還是存有一份資訊,不消費,攢著留著過年嗎?
第2個條件還能通過設置過期解決,第1個條件,都不知道什麼應用場景才適合,但肯定不屬於MQ的應用場景。
總結:
還是一句話:它是隊列,不是資料庫,無法根據條件過濾過查詢。