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#
- Send可以发送3种类型的消息, game, sport, music
- 发送消息时必须指定消息的类型
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#
- Receive可以接收3种类型的消息, game, sport, music
- 程序启动时指定接收的消息类型
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类型的消息。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?