RabbitMQ Publish/Subscribe Direct, Topic And Header Type
今天要來學習發布訂閱模式中的 Direct
和 Topic
模式這兩個模式使用起來非常相似。上一篇文章中我們學習到的 Fanout
模式有一個不太方便的點,那就是
它會一次發送給有綁定到 Exchange
上的所有 Queue
,如果只想要發送給某個特定族群的 Queue
就可以選擇使用 Direct
, Topic
或者 Header
模式。
Direct Type
Direct
從字面上來看就是直接的意思,還記得在第一篇文章中我們不使用 Exchange
直接使用 routingKey
發送到有同樣名稱的 Queue
嗎?
Direct
模式也是使用 routingKey
來決定要發送到哪些 Queue
,不過不同的是點對點模式中的 routingKey
需要輸入明確的 Queue
名稱,
但是在 Direct
模式的 routingKey
比較像群組的概念,我們需要先將多個 Queue
設定同一個群組才能使用 Direct
模式。
首先我們到 Receive
專案,定義一個新的 Direct
類型的 Exchange
,並且建立一個隨機名稱的 Queue
並且 routingKey
會根據我們之後傳入的參數來設定
channel.ExchangeDeclare("direct_exchange", ExchangeType.Direct);
var queueName = channel.QueueDeclare().QueueName;
channel.QueueBind(queueName, "direct_exchange", string.Join("", args));
接下來開啟兩個 shell
並運行 Receive
專案
#shell 1
dotnet run "group1"
#shell 1
dotnet run "group2"
接下來修改 Send
專案,定義一個新的 Direct
類型的 Exchange
,在發送信息時選擇發送到 group1
channel.ExchangeDeclare("direct_exchange", ExchangeType.Direct);
channel.BasicPublish(exchange: "direct_exchange",
routingKey: "group1",
mandatory: true,
basicProperties: null,
body: body);
這樣當我們直接執行 Send
專案會直接發送到有相同 routingKey
的 Queue
,擁有不同的 routingKey
則不會收到信息
#shell 1
dotnet run "group1"
[*] Waiting for messages.
Press [enter] to exit.
[x] Received Hello World!
[x] Done
#shell 2
dotnet run "group2"
[*] Waiting for messages.
Press [enter] to exit.
你也可以在開啟一個 shell 3
並設定為 group1
,可以看到 shell 1
與 shell 3
能夠順利收到 Hello World 信息。
Topic Type
Topic
類型與 Direct
相比之下擁有更高的彈性,在 Topic
類型中我們可以使用兩個符號即可做到 wildcard 的功能,就可以同時匹配多個 routingKey
,
-
- (star) 可以匹配一個單詞
(hash) 可以匹配一個單詞或多個單詞
這邊每個單詞需要用 .
來分割例如我們在定義 routingKey
時可以輸入以下格式 group.*
,假如我們想要發送給 group.1
或 group.2
因為都符合
group.*
格式因此這兩個群組的信息都可以收到
我們先到 Receive
專案,定義一個新的 Topic
類型的 Exchange
channel.ExchangeDeclare("topic_exchange", ExchangeType.Topic);
var queueName = channel.QueueDeclare().QueueName;
channel.QueueBind(queueName, "topic_exchange", string.Join("", args));
接下來開啟兩個 shell
並運行 Receive
專案
#shell 1
dotnet run "*.group.*"
#shell 2
dotnet run "vip.group.1"
接下來修改 Send
專案,定義一個新的 Direct
類型的 Exchange
,在發送信息時選擇發送到 vip.group.1
channel.ExchangeDeclare("topic_exchange", ExchangeType.Topic);
channel.BasicPublish(exchange: "topic_exchange",
routingKey: "vip.group.1",
mandatory: true,
basicProperties: null,
body: body);
可以看到 shell1
使用了星字號代表可以替代整個單詞,因此可以接收到 vip.group.1
的信息
#shell 1
dotnet run "*.group.*"
[*] Waiting for messages.
Press [enter] to exit.
[x] Received Hello World!
[x] Done
#shell 2
dotnet run "vip.group.1"
[*] Waiting for messages.
Press [enter] to exit.
[x] Received Hello World!
[x] Done
並且我們知道井字號代表可以替換一個或多個單詞,因此只要 routingKey
直接輸入井字號就代表可以接收所有信息
#shell 1
dotnet run "#"
Header Type
最後一個 Exchange
類型是 Header
這個類型概念也相同不過 Header
類型會忽略 routingKey
的值,因此我們需要額外定義一組 Header
字典
來提供之後進行匹配。
先到 Receive
專案,定義一個新的 Header
類型的 Exchange
,並且定義一個字典我們可以設定多個 key
,value
值,這邊需要注意 x-match
有兩個設定值可以使用分別是 all
和 any
, all
代表需要匹配所有的 key
,value
值,any
代表只需要匹配其中一個的 key
,value
值
channel.ExchangeDeclare("header_exchange", ExchangeType.Headers);
var queueName = channel.QueueDeclare().QueueName;
var header = new Dictionary<string, object>()
{
{ "group", "vip" },
{ "level", "1" },
{ "x-match", "any" }
};
channel.QueueBind(queueName, "header_exchange", string.Empty, header);
接下來修改 Send
專案,定義一個新的 Direct
類型的 Exchange
channel.ExchangeDeclare("header_exchange", ExchangeType.Headers);
var properties = channel.CreateBasicProperties();
properties.Headers = new Dictionary<string, object>()
{
{"group", "vip"},
{"level", "2"},
};
channel.BasicPublish(exchange: "header_exchange",
routingKey: string.Empty,
mandatory: true,
basicProperties: properties,
body: body);
接下來運行 Receive
和 Send
專案,這邊因為 x-match
設定為 any
因此雖然只有 {"group", "vip"}
這組符合但是還是能階收到信息
dotnet run
[*] Waiting for messages.
Press [enter] to exit.
[x] Received Hello World!
[x] Done
Summary
今天學習剩下的三種發布訂閱模式 Direct
, Topic
和 Header
模式,可以看得出來 Direct
和 Topic
本質上幾乎是一樣的因此直接使用 Topic
模式是比較好的選擇,另外 Header
模式因為可以同時設定多個 key
, value
值擁有更高的彈性,之後可以按照自己的需求來選擇。
今天的進度 Github