(五)「消息队列」之 RabbitMQ 主题(使用 .NET 客户端)

0、引言

先决条件

本教程假设 RabbitMQ 已安装并且正在 本地主机 的标准端口(5672)上运行。如果您使用了不同的主机、端口或凭证,则要求调整连接设置。

获取帮助

如果您在阅读本教程时遇到问题,可以通过邮件列表或者 RabbitMQ 社区 Slack 与 RabbitMQ 官方取得联系。

在上一篇教程中我们改进了日志系统。我们没有使用只能进行虚拟广播的 fanout 交换机,而是使用了 direct 直连交换机,从而获得了选择性接收日志的可能性。

尽管使用了 direct 直连交换机改进了我们的系统,但它仍然有局限性 —— 它不能基于多个标准进行路由。

在我们的日志系统中,我们可能不仅希望订阅根据严重程度区分的日志,还希望订阅根据来源区分的日志。您可能从 syslog unix 工具中了解过这个概念,它根据严重程度(info/warn/crit…)和设备(auth/cron/kern…)路由日志。

这可以给我们很大的灵活性 —— 我们也许希望仅了解来自于 ‘corn’ 的关键错误,但同样也希望了解来自于 ‘kern’ 的所有日志。

为了在我们的日志系统中实现这一点,我们需要学习一种更复杂的 topic 主题交换机。

原文链接:https://www.rabbitmq.com/tutorials/tutorial-five-dotnet.html

1、主题交换机

发送给 topic 主题交换机的消息不能有任意的路由键 —— 它只能是一个由点分隔的单词列表。单词可以是任何东西,但通常它们指定与消息相关的一些特征。下面是一些有效的路由键示例:“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”。路由键中可以有任意多的单词,最多不超过 255 字节。

绑定键也必须是同样的形式。topic 主题交换机背后的逻辑与 direct 直连交换机类似 —— 使用特定 routing key 路由键发送的消息将被传递给使用匹配 binding key 绑定键绑定的所有队列。但是,绑定键有两种重要的特殊情况:

  • *(星号)只能匹配一个单词。
  • #(井号)可以匹配零或者多个单词。

用一个例子来解释这一点最简单:

tutorial-five

在这个例子当中,我们将会发送一些均用来描述动物的消息。我们将会使用包含三个单词(两个点)的 routing key 路由键发送这些消息。路由键中的第一个单词用于描述速度,第二个描述颜色以及第三个描述物种:“<speed>.<colour>.<species>”。

我们创建三个绑定:Q1 使用 “*.orange.*” 绑定键绑定;Q2 使用 “*.*.rabbit” 和 “lazy.#” 绑定。

这些绑定可以被总结为:

  • Q1 对所有的橙色动物感兴趣。
  • Q2 想知道关于兔子以及懒惰动物的一切信息。
  1. 带有 “quick.orange.rabbit” 路由键的消息将被同时传递给两个队列。“lazy.orange.elephant” 消息同样也会同时前往两个队列。
  2. 另一方面,“quick.orange.fox” 只会前往 Q1,而 “lazy.brown.fox” 只会前往 Q2
  3. lazy.pink.rabbit” 只会被传递给 Q2 一次,即便它与两个绑定匹配。
  4. quick.brown.fox” 不匹配任何绑定,因此将被丢弃。

如果我们违反约定,发送带有一个或者四个单词的消息(比如 “orange” 或者 “quick.orange.new.rabbit”),会发生什么呢?好吧,这些消息将不会匹配任何绑定并且丢失。

另一方面,即便 “lazy.orange.new.rabbit” 有四个单词,但仍然匹配最后一个绑定,所以将会被传递给 Q2 队列。

主题交换机

主题交换机十分强大并且能够模拟其他交换机。

当一个队列使用 “#”(井号)绑定键绑定时 —— 它将会忽略路由键接收所有消息 —— 就像 fanout 扇出交换机那样。

当绑定中不使用 “*”(星号)与 “#”(井号)特殊字符时,topic 主题交换机将会表现得像是 direct 直连交换机。

2、将所有的东西放到一起

我们将在日志系统中使用 topic 主题交换机。我们将从一个工作假设开始:即日志的路由键将有两个单词:“<facility>.<severity>”。

代码几乎与上一篇教程中一致。

EmitLogTopic.cs 的代码:

using System.Text;
using RabbitMQ.Client;var factory = new ConnectionFactory { HostName = "localhost" };using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();channel.ExchangeDeclare(exchange: "topic_logs", type: ExchangeType.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 '{routingKey}':'{message}'");

ReceiveLogsTopic.cs 的代码:

using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;var factory = new ConnectionFactory { HostName = "localhost" };using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();channel.ExchangeDeclare(exchange: "topic_logs", type: ExchangeType.Topic);
// declare a server-named queue
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.ToArray();var message = Encoding.UTF8.GetString(body);var routingKey = ea.RoutingKey;Console.WriteLine($" [x] Received '{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.cs 和 ReceiveLogsTopic.cs 的完整源码)

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

5、生产[非]适用性免责声明

请记住,本教程和其他教程都是教程。他们一次展示一个新概念,可能会有意地过度简化一些东西,而忽略其他东西。例如,为了简洁起见,连接管理、错误处理、连接恢复、并发性和指标收集等主题在很大程度上被省略了。这种简化的代码不应该被认为可以用于生产。

在发布您的应用之前,请先查看其他文档。我们特别推荐以下指南:发布者确认和消费者确认,生产清单和监控。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/3340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

56 # 实现 pipe 方法进行拷贝

pipe 是异步的&#xff0c;可以实现读一点写一点&#xff0c;管道的优势&#xff1a;不会淹没可用内存&#xff0c;但是在导入的过程中无法获取到内容 const fs require("fs"); const path require("path");fs.createReadStream(path.resolve(__dirname…

前端 | (七)浮动 | 尚硅谷前端html+css零基础教程2023最新

学习来源&#xff1a;尚硅谷前端htmlcss零基础教程&#xff0c;2023最新前端开发html5css3视频 文章目录 &#x1f4da;浮动介绍&#x1f407;元素浮动后的特点&#x1f407;浮动小练习&#x1f525;盒子1右浮动&#x1f525;盒子1左浮动&#x1f525;所有盒子都浮动&#x1f5…

Python 闭包 装饰器

闭包定义&#xff1a;在函数嵌套的前提下&#xff0c;内部函数使用了外部函数的变量&#xff0c;并且外部函数返回了内部函数&#xff0c;我们把这个使用外部函数变量的内部函数称为闭包. 下面实现一个在执行方法的前后打印日志的场景 第一种方法装饰器 1.定义外层函数(要求…

vscode 添加 ros头文件

解决 vscode不能支持ROS相关头文件和没有智能提示问题 vscode 编写pakage源文件代码,#include<ros/ros.h>等头文件时报错,无法运行智能提示 1.vscode中CTRL+P 2.键入ext install ms-iot.vscode-ros 按回车,等待下载ros插件 3.修改c_cpp_properties.json文件 鼠标…

数学建模 插值算法

有问题 牛顿差值也有问题它们都有龙格现象&#xff0c;一般用分段插值。 插值预测要比灰色关联预测更加准确&#xff0c;灰色预测只有2次 拟合样本点要非常多&#xff0c;样本点少差值合适

Spring底层

配置文件 配置优先级 之前讲解过&#xff0c;可以用这三种方式进行配置 那如果这三种都进行了配置&#xff0c;那到底哪一份生效呢&#xff1f; 结论 优先级从大到小 properties>yml>yaml然后就是现在一般都用yml文件进行配置 其他配置方式 除了配置文件外 还有不同…

java Spring中使用到的设计模式

单例模式 单例模式(Singleton Pattern)是java中最简单的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类&#xff0c;该类负责创建自己的对象&#xff0c;同时确保只有单个对象被创建。这个类提供了一…

电压放大器在超声波焊接中的作用以及应用

电压放大器是一种运用于电子设备中的信号放大器&#xff0c;主要作用是将小信号放大为更高幅度的信号。在超声波焊接中&#xff0c;电压放大器起到了重要的作用&#xff0c;它可以将从传感器采集到的微小信号放大为能够被检测和处理的合适大小的信号。 超声波焊接是现代工业生产…

微信怎么自动加好友,通过好友后自动打招呼

很多客户朋友每天花大量的时间用手机搜索添加好友&#xff0c;这样的添加很集中也容易频繁&#xff0c;而且效率还低。对方通过后&#xff0c;有时也不能及时和客户搭建链接&#xff0c;导致客户也流失了。 现在可以实现自动添加和自动打招呼哦&#xff0c;只需要导入数据、设置…

【从零开始学CSS | 第二篇】伪类选择器

目录 前言&#xff1a; 伪类选择器&#xff1a; 常见的伪类选择器&#xff1a; 举例&#xff1a; 小窍门&#xff1a; 总结: 前言&#xff1a; 上一篇文章我们详细的为大家介绍了一些常见的选择器&#xff0c;这几篇我们将再次介绍CSS中的一个常见选择器——伪类选择器&am…

设计模式之适配器模式

写在前面 适配器设计模式属于结构型设计模式的一种&#xff0c;本文一起来看下。 1&#xff1a;介绍 1.1&#xff1a;什么时候适配器设计模式 当现有接口客户端无法直接调用时&#xff0c;我们可以考虑适配器设计模式&#xff0c;来定义一个能够供客户端直接调用的接口&…

软件测试的分类

代码分类&#xff1a; 1、黑盒测试 2、白盒测试 3、灰黑测试 黑盒测试&#xff1a; 把测试的对象看成是一个黑色的盒子的&#xff0c;看不到里面内部的结构&#xff0c;是对软件的一种功能性的测试。 白盒测试&#xff1a; 就是把测试的对象看成是一个透明的盒子&#x…

测试老鸟总结,性能测试-最佳并发和最大并发,性能测试实施...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试&#xf…

curl操作

下载路径&#xff1a;https://curl.se/windows/ 参考&#xff1a;https://blog.csdn.net/weixin_45191386/article/details/130652821 操作&#xff1a; curl http://localhost:8085/api/v1/aaa/bbbb/?ccc 652781344055627776

Maven下载依赖的顺序及配置文件说明

在 Maven 中&#xff0c;当下载依赖项时&#xff0c;存在多个仓库时会按照以下优先级顺序进行搜索&#xff1a; 本地仓库&#xff1a;Maven 会首先在本地的 Maven 仓库中查找依赖项。 私有仓库&#xff08;私服&#xff09;&#xff1a;如果在本地仓库中未找到依赖项&#xf…

编程导航算法村第二关 | 白银挑战

编程导航算法村第二关 | 白银挑战 指定区间的链表翻转 LeetCode92 &#xff1a;给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回反转后的链表。 public ListNode revers…

第四次CCF计算机软件能力认证

第一题&#xff1a;图像旋转 旋转是图像处理的基本操作&#xff0c;在这个问题中&#xff0c;你需要将一个图像逆时针旋转 90 度。 计算机中的图像表示可以用一个矩阵来表示&#xff0c;为了旋转一个图像&#xff0c;只需要将对应的矩阵旋转即可。 输入格式 输入的第一行包含两…

我国版式文档格式OFD前端WEB展示之EasyOFD

EasyOFD an ofd file web shower 一个在web端展示ofd文件的控件&#xff0c;该控件基于CANVAS绘制。 该控件使用了以下外部程序 1&#xff09;jszip&#xff1a;解决解压文件。 2&#xff09;x2js: 解决XML文件到JS转换 3&#xff09;easyjbig2: 解决ofd内部使用jb2文件存储的…

NSSCTF刷web(2)

[NISACTF 2022]bingdundun~ bingdundun处感觉像文件包含,改upload为index 发现确实,猜测会补一个后缀.php 那常规文件包含都不行了,这里还有一个文件上传的功能,考虑phar协议 <?php$phar new Phar("test.phar"); $phar->startBuffering(); $phar->setStu…

小马识途分享百度百科收录词条的规则

百度百科词条是人人都可以编辑的&#xff0c;并且都是免费创建&#xff0c;但是自己创建百科词条往往审核不通过&#xff0c;一般企业会把这项任务委托给有经验的营销团队。这里小马识途营销顾问分享一下百度百科收录词条的规则。 百度百科收录规则主要分为&#xff1a;规范词条…