[译]RabbitMQ教程C#版 - 主题

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 先决条件本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672)。如果你使用不同的主机、端口或证书,则需要调整连接设置。从哪里获得帮助如果您在阅读本教程时遇到困难,可以通过邮件列表 联系我们。

先决条件
本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672)。如果你使用不同的主机、端口或证书,则需要调整连接设置。

从哪里获得帮助
如果您在阅读本教程时遇到困难,可以通过邮件列表 联系我们

主题

(使用.NET客户端)

教程[4] 中,我们改进了我们日志系统。我们用direct交换器替换了只能呆滞广播消息的fanout交换器,从而可以有选择性的接收日志。

虽然使用direct交换器改进了我们的系统,但它仍然有局限性 - 不能基于多个标准进行路由。

在我们的日志系统中,我们可能不仅要根据日志的严重性订阅日志,可能还要根据日志分发源来订阅日志。或许您可能从 unix syslog 工具中了解过这种概念,syslog 工具在路由日志的时候是可以既基于严重性(info/warn/crit...)又基于设备(auth/cron/kern...)的。

这种机制会给我们带来极大的灵活性 - 我们可以仅监听来自cron的关键错误日志,与此同时,监听来自kern的所有日志。

要在我们的日志系统中实现这一特性,我们需要学习更复杂的topic交换器。

Topic交换器

发送到topic交换器的消息不能随意指定routing key,它必须是一个由点分割的单词列表,这些单词可以是任意内容,但通常会在其中指定一些与消息相关的特性。请看一些合法的路由键示例:stock.usd.nysenyse.vmwquick.orange.rabbit,路由键可以包含任意数量的单词,但不能超过255个字节的上限。

binding key也必须是相同的形式,topic交换器的背后逻辑与direct交换器类似 - 使用指定路由键发送的消息会被分发到与其绑定键匹配的所有队列中。不过对于绑定键来说,有两个重要的特殊情况需要注意:

  • *(星号)可以代替一个单词。
  • #(哈希)可以代替零个或多个单词。

下图示例是对上述内容最简单的解释:

image

在这个示例中,我们打算发送的消息全是用来描述动物的,这些消息会使用由三个单词(两个点)组成的路由键来发送。在路由键中,第一个单词用来描述行动速度、第二个是颜色、第三个是物种,即:<speed>.<colour>.<species>

我们创建了三个绑定:Q1绑定了键.orange.,Q2绑定了键*.*.rabbitlazy.#

这些绑定可以被概括为:

  • Q1对所有橙色的动物感兴趣。
  • Q2对兔子以及所有行动缓慢的动物感兴趣。

路由键为quick.orange.rabbit的消息会被发送到这两个队列,消息lazy.orange.elephant也会被发送到这两个队列。另外,quick.orange.fox只会进入第一个队列,lazy.brown.fox只会进入第二个队列。lazy.pink.rabbit只会被发送到第二个队列一次,尽管它匹配了两个绑定(避免了消息重复)。quick.brown.fox没有匹配的绑定,因此它将会被丢弃。

如果我们打破约定,发送使用一个或四个单词(例如:orangequick.orange.male.rabbit)作路由键的消息会发生什么?答案是,这些消息因为没有匹配到任何绑定,将被丢弃。

但是,另外,例如路由键为lazy.orange.male.rabbit的消息,尽管它有四个单词,也会匹配最后一个绑定,并将被发送到第二个队列。

Topics 交换器

topic交换器的功能是很强大的,它可以表现出一些其他交换器的行为。

当一个队列与键(哈希)绑定时, 它会忽略路由键,接收所有消息,这就像fanout交换器一样。

当特殊字符*(星号)和(哈希)未在绑定中使用时,topic交换器的行为就像direct交换器一样。

组合在一起

我们将要在我们的日志系统中使用topic交换器,首先假设日志的路由键有两个单词组成:<facility>.<severity>

代码与上一篇 教程 中的代码几乎相同。

EmitLogTopic.cs的代码:

using System;
using System.Linq;
using RabbitMQ.Client;
using System.Text;

class EmitLogTopic
{
    public static void Main(string[] args)
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using(var connection = factory.CreateConnection())
        using(var channel = connection.CreateModel())
        {
            channel.ExchangeDeclare(exchange: "topic_logs",
                                    type: "topic");

            var routingKey = (args.Length > 0) ? args[0] : "anonymous.info";
            
            var message = (args.Length > 1)
                          ? string.Join(" ", args.Skip(1).ToArray())
                          : "Hello World!";
            var body = Encoding.UTF8.GetBytes(message);
            
            channel.BasicPublish(exchange: "topic_logs",
                                 routingKey: routingKey,
                                 basicProperties: null,
                                 body: body);
                                 
            Console.WriteLine(" [x] Sent '{0}':'{1}'", routingKey, message);
        }
    }
}

ReceiveLogsTopic.cs的代码:

using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

class ReceiveLogsTopic
{
    public static void Main(string[] args)
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using(var connection = factory.CreateConnection())
        using(var channel = connection.CreateModel())
        {
            channel.ExchangeDeclare(exchange: "topic_logs", type: "topic");
            var queueName = channel.QueueDeclare().QueueName;

            if(args.Length < 1)
            {
                Console.Error.WriteLine("Usage: {0} [binding_key...]",
                                        Environment.GetCommandLineArgs()[0]);
                Console.WriteLine(" Press [enter] to exit.");
                Console.ReadLine();
                Environment.ExitCode = 1;
                return;
            }

            foreach(var bindingKey in args)
            {
                channel.QueueBind(queue: queueName,
                                  exchange: "topic_logs",
                                  routingKey: bindingKey);
            }

            Console.WriteLine(" [*] Waiting for messages. To exit press CTRL+C");

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                var routingKey = ea.RoutingKey;
                Console.WriteLine(" [x] Received '{0}':'{1}'",
                                  routingKey,
                                  message);
            };
            channel.BasicConsume(queue: queueName,
                                 autoAck: true,
                                 consumer: consumer);

            Console.WriteLine(" Press [enter] to exit.");
            Console.ReadLine();
        }
    }
}

请运行以下示例:

要接收所有日志:

cd ReceiveLogsTopic
dotnet run "#"

要接收来自设备kern的所有日志:

cd ReceiveLogsTopic
dotnet run "kern.*"

或者,如果您只想监听级别为critical的日志:

cd ReceiveLogsTopic
dotnet run "*.critical"

您可以创建多个绑定:

cd ReceiveLogsTopic
dotnet run "kern.*" "*.critical"

使用路由键kern.critical发出日志:

cd EmitLogTopic
dotnet run "kern.critical" "A critical kernel error"

希望运行这些程序能让您玩得开心。要注意的是,这些代码没有针对路由键和绑定键做任何预设,您可以尝试使用两个以上的路由键参数。

EmitLogTopic.csReceiveLogsTopic.cs 的完整源码)

接下来,在 教程[6] 中将了解如何将往返消息作为远程过程调用。

写在最后

本文翻译自RabbitMQ官方教程C#版本。如本文介绍内容与官方有所出入,请以官方最新内容为准。水平有限,翻译的不好请见谅,如有翻译错误还请指正。

  • 原文链接:RabbitMQ tutorial - Topics

  • 实验环境:RabbitMQ 3.7.4 、.NET Core 2.1.3、Visual Studio Code

  • 最后更新:2018-09-06

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
4月前
|
消息中间件 Java RocketMQ
RocketMQ实战教程之RocketMQ安装
这是一篇关于RocketMQ安装的实战教程,主要介绍了在CentOS系统上使用传统安装和Docker两种方式安装RocketMQ。首先,系统需要是64位,并且已经安装了JDK 1.8。传统安装包括下载安装包,解压并启动NameServer和Broker。Docker安装则涉及安装docker和docker-compose,然后通过docker-compose.yaml文件配置并启动服务。教程还提供了启动命令和解决问题的提示。
|
14天前
|
设计模式 C# 开发者
C#设计模式入门实战教程
C#设计模式入门实战教程
|
1月前
|
网络协议 物联网 测试技术
App Inventor 2 MQTT拓展入门(保姆级教程)
本文演示的是App和一个测试客户端进行消息交互的案例,实际应用中,我们的测试客户端可以看着是任意的、支持MQTT协议的硬件,通过订阅及发布消息,联网硬件与我们的App进行双向数据通信,以实现万物互联的智能控制效果。
126 2
|
27天前
|
消息中间件 监控 Ubuntu
RabbitMQ安装配置,超详细版教程
以上步骤为您提供了在Linux环境下安装RabbitMQ的详细过程。安装Erlang作为基础,然后通过添加官方源并安装RabbitMQ本身,最后对服务进行配置并启用Web管理界面。这些步骤操作简单直观,只需要跟随上述指南,即可在短时间内将RabbitMQ服务器运行起来,并进行进一步的配置和管理。不要忘记硬件和网络资源对性能的影响,确保RabbitMQ能够满足您的应用需求。
76 0
|
2月前
|
消息中间件 搜索推荐 RocketMQ
消息队列 MQ使用问题之如何将一个主题的多个分区分布到不同的Broker上
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
2月前
|
机器学习/深度学习 算法 搜索推荐
一个开源且全面的C#算法实战教程
一个开源且全面的C#算法实战教程
|
4月前
|
消息中间件 存储 Apache
RocketMQ实战教程之常见概念和模型
Apache RocketMQ 实战教程介绍了其核心概念和模型。消息是基本的数据传输单元,主题是消息的分类容器,支持字节、数字和短划线命名,最长64个字符。消息类型包括普通、顺序、事务和定时/延时消息。消息队列是实际存储和传输消息的容器,是主题的分区。消费者分组是一组行为一致的消费者的逻辑集合,也有命名限制。此外,文档还提到了一些使用约束和建议,如主题和消费者组名的命名规则,消息大小限制,请求超时时间等。RocketMQ 提供了多种消息模型,包括发布/订阅模型,有助于理解和优化消息处理。
|
3月前
|
消息中间件 Java RocketMQ
教程:Spring Boot整合RocketMQ的配置与优化
教程:Spring Boot整合RocketMQ的配置与优化
|
4月前
|
消息中间件 存储 Java
RocketMQ实战教程之NameServer与BrokerServer
这是一个关于RocketMQ实战教程的概要,主要讨论NameServer和BrokerServer的角色。NameServer负责管理所有BrokerServer,而BrokerServer存储和传输消息。生产者和消费者通过NameServer找到合适的Broker进行交互,不需要直接知道Broker的具体信息。工作流程包括生产者向NameServer查询后发送消息到Broker,以及消费者同样通过NameServer获取消息进行消费。这种设计类似于服务注册中心的概念,便于系统扩展和集群管理。
|
3月前
|
消息中间件 Java Spring
最新spingboot整合rabbitmq详细教程
最新spingboot整合rabbitmq详细教程