RabbitMQ学习笔记(四) Routing

新的场景

在我们学习了RabbitMQ的发布与订阅之后,我们很容易就可以完成一个简单的消息群发器。

使用这个消息群发器,所有的消费者程序实例都会接收到相同的消息信息,从而实现广播的效果。

但是这种广播是一种无意识的广播,即使消息是有分类的,消费者程序也不能自己决定关注的消息类型,只能被动的接收所有的消息,这就导致消费者程序收到许多无用的消息。

如果想要消费者程序自主决定关注的消息类型,我们可以使用RabbitMQ的Routing机制。

Binding

之前学习RabbitMQ的发布与订阅,我们使用如下代码将消息队列和Exchange进行绑定。

1
channel.QueueBind(queue: queueName, exchange: "broadcast", routingKey: "");

 

其中有一个参数是routingKey, 我们将它设置为空。

对于fanout类型的Exchange, 在绑定消息队列和Exchange的时候,会自动忽略routingKey。

但是Direct类型的Exchange使用这个参数可以帮助我们对消息进行的分类,这里我们可以简单的认为routingKey就是一种消息类型

Direct Exchange

Direct的路由算法很简单,它会将消息发送到与Direct  Exchange绑定并拥有指定routingKey的消息队列中。

 

一个消息队列与一个Direct Exchange绑定的时候,可以通过多次绑定,拥有多个routingKey。

同理,一个routingKey也可以被多个消息队列拥有。

例:

1
2
3
channel.QueueBind(queue: queueName, exchange: "broadcast", routingKey: "key1");
 
channel.QueueBind(queue: queueName, exchange: "broadcast", routingKey: "key2");



 

 

 

在发布与订阅中,我们使用生产者程序向Fanout Exchange发送消息的时候,编写了如下代码

1
2
3
4
5
6
7
8
9
channel.BasicPublish(exchange: "broadcast",
 
                        routingKey: "",
 
                        basicProperties: null,
 
                        body: body
 
                    );



 

其中routingKey为空, 因为Fanout Exchange并不关心routingKey。

现在我们使用Direct Exchange, 我们需要指定消息类型routingKey。当Direct Exchnage接收到这条消息之后,它查找和他绑定的所有消息队列,如果消息队列拥有这个routingKey,Direct Exchange就会将这条消息传输给它, 这样监听该消息队列的消费者程序就可以接收到这条消息。

修改代码

Send#

  1. Send可以发送3种类型的消息, game, sport, music
  2. 发送消息时必须指定消息的类型

 

       

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
static string[] availableTypes = { "game", "music", "sport" };
 
  
 
        static void Main(string[] args)
 
        {
 
            if (args == null || args.Length == 0)
 
            {
 
                Console.WriteLine("This command line should be like 'dotnet run [message type] [message].'");
 
                Environment.Exit(1);
 
            }
 
  
 
            var messageType = args[0];
 
  
 
            if (!availableTypes.Contains(messageType))
 
            {
 
                Console.WriteLine("Available message type can be 'game','music','sport'.");
 
                Environment.Exit(1);
 
            }
 
  
 
            var factory = new ConnectionFactory()
 
            {
 
                HostName = "localhost"
 
            };
 
  
 
            using (var connection = factory.CreateConnection())
 
            {
 
                using (var channel = connection.CreateModel())
 
                {
 
                    channel.ExchangeDeclare("broadcast", "direct");
 
  
 
                    string message = $"{args[0]} news: {args[1]}";
 
                    var body = Encoding.UTF8.GetBytes(message);
 
  
 
                    channel.BasicPublish(exchange: "broadcast",
 
                        routingKey: messageType,
 
                        basicProperties: null,
 
                        body: body
 
                    );
 
  
 
                    Console.WriteLine("[x] Sent {0}", message);
 
                }
 
            }
 
        }

 

 

 

 

Receive#

  1. Receive可以接收3种类型的消息, game, sport, music
  2. 程序启动时指定接收的消息类型

 

       

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
static string[] availableTypes = { "game", "music", "sport" };
 
  
 
        static void Main(string[] args)
 
        {
 
            if (args == null || args.Length == 0)
 
            {
 
                Console.WriteLine("This command line should be like 'dotnet run [message type 1] [message type 2] [message type 3].'");
 
                Environment.Exit(1);
 
            }
 
  
 
            foreach (var type in args)
 
            {
 
                if (!availableTypes.Contains(type))
 
                {
 
                    Console.WriteLine("Available message type can be 'game','music','sport'.");
 
                    Environment.Exit(1);
 
                }
 
            }
 
  
 
            var factory = new ConnectionFactory() { HostName = "localhost" };
 
  
 
            using (var connection = factory.CreateConnection())
 
            {
 
                using (var channel = connection.CreateModel())
 
                {
 
                    channel.ExchangeDeclare("broadcast", "direct");
 
  
 
                    var queueName = channel.QueueDeclare().QueueName;
 
  
 
                    foreach (var type in args)
 
                    {
 
                        channel.QueueBind(queue: queueName, exchange: "broadcast", routingKey: type);
 
                    }
 
  
 
                    var consumer = new EventingBasicConsumer(channel);
 
  
 
                    consumer.Received += (model, ea) =>
 
                    {
 
                        var body = ea.Body;
 
                        var message = Encoding.UTF8.GetString(body);
 
                        Console.WriteLine("[x] Received {0}", message);
 
                    };
 
  
 
                    channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
 
  
 
                    Console.Read();
 
                }
 
            }
 
        }

 

 

最终效果

启动1个Send, 2个Receive。

一个Receive关注game, music类型的消息。

一个Receive关注sport, game类型的消息。

posted @   LamondLu  阅读(295)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示
主题色彩