(五)「消息队列」之 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.mfbz.cn/a/40284.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】list的使用及底层实现原理

本篇文章对list的使用进行了举例讲解。同时也对底层实现进行了讲解。底层的实现关键在于迭代器的实现。希望本篇文章会对你有所帮助。 文章目录 一、list的使用 1、1 list的介绍 1、2 list的使用 1、2、1 list的常规使用 1、2、2 list的sort讲解 二、list的底层实现 2、1 初构…

windows环境hadoop报错‘D:\Program‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Hadoop版本为2.7.3&#xff0c;在环境配置好后&#xff0c;检查hadoop安装版本&#xff0c;报如标题所示错误&#xff0c;尝试网上主流的几种方法均无效。 错误&#xff1a;windows环境hadoop报错’D:\Program’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 错误方…

perl输出中文乱码【win10】

perl输出中文乱码 运行的时候输出的内容变成了中文乱码&#xff0c;原因首先来查找一下自己的perl的模块里面是否有Encode-CN。请运行打开你的cmd并输入perldoc -l Encode::CN 如果出现了地址 则就是有&#xff0c;如果没有需要进行该模块的安装。 安装方式有很多种&#xff0…

STM32F407-- DMA使用

目录 1. DMA结构体 STM32F103&#xff1a; STM32F407&#xff1a; 2. F4系列实现存储器到存储器数据传输 1&#xff09;结构体配置&初始化 2&#xff09;主函数 补充知识点&#xff1a;关于变量存储的位置&#xff0c;关于内部存储器一般存储什么内容 3. F4系列实现…

机器学习 day26(多标签分类,Adam算法,卷积层)

1. 多标签分类 多标签分类&#xff1a;对于单个输入特征&#xff0c;输出多个不同的标签y多类分类&#xff1a;对于单个输入特征&#xff0c;输出单个标签y&#xff0c;但y的可能结果有多个 2. 为多标签分类构建神经网络模型 我们可以构建三个不同的神经网络模型来分别预测…

C++第四讲

思维导图 仿照string类&#xff0c;实现myString类 /* ---------------------------------author&#xff1a;YoungZorncreated on 2023/7/19 19:20.--------------------------------- */ #include<iostream> #include<cstring>using namespace std;class myStri…

搜索引擎elasticsearch :安装elasticsearch (包含安装组件kibana、IK分词器、部署es集群)

文章目录 安装elasticsearch1.部署单点es1.1.创建网络1.2.加载镜像1.3.运行 2.部署kibana2.1.部署2.2.DevTools2.3 分词问题(中文不友好) 3.安装IK分词器3.1.在线安装ik插件&#xff08;较慢&#xff09;3.2.离线安装ik插件&#xff08;推荐&#xff09;1&#xff09;查看数据卷…

APP测试学习之Android模拟器Genymotion安装配置不上解决方法以及adb基本使用

Android模拟器Genymotion安装配置不上解决方法以及adb基本使用 Genymotion下载安装配置遇见的问题解决方法adb基本使用 Genymotion下载 1.首先进入官网 https://www.genymotion.com/ 2.在官网注册一个账号 https://www-v1.genymotion.com/account/login/ 3.下载 https://www.g…

Git源代码管理方案

背景 现阶段的Git源代码管理上有一些漏洞&#xff0c;导致在每次上线发布的时间长、出问题&#xff0c;对整体产品的进度有一定的影响。 作用 新的Git源代码管理方案有以下作用&#xff1a; 多功能并行开发时&#xff0c;测试人员可以根据需求任务分配测试自己的功能&#…

单片机第一季:零基础9——直流电机和步进电机

目录 1&#xff0c;直流电机 2&#xff0c;步进电机 1&#xff0c;直流电机 直流电机是指能将直流电能转换成机械能&#xff08;直流电动机&#xff09;或将机械能转换成直流电能&#xff08;直流发电机&#xff09;的旋转电机。它是能实现直流电能和机械能互相转换的电机。…

大模型开发(八):基于思维链(CoT)的进阶提示工程

全文共8000余字&#xff0c;预计阅读时间约16~27分钟 | 满满干货&#xff08;附复现代码&#xff09;&#xff0c;建议收藏&#xff01; 本文目标&#xff1a;介绍提示工程基础类方法、思维链提示方法和LtM的提示方法&#xff0c;并复现解决论文中四个经典推理问题。 代码下载…

Spring实现文件上传,文件上传

第一步&#xff1a;创建jsp文件 创建form表单 提交文件是post 文件上传的表单 服务端能不能获得数据&#xff0c;能 实现单文件上传的步骤&#xff1a; 导入相应的坐标&#xff1a;在pom.xml文件中进行导入 再导入这份&#xff1a; 第二步&#xff0c;在spring-MVC的上传中去配…

React中使用Redux

1.为什么要使用redux redux是一个专门用于状态管理的一个库&#xff0c;和vue中的vuex功能类似。其中核心点就是状态的管理。虽然我们无论在vue还是在react中我们组件间的通行都可以使用消息总线或者父子组件间的消息传递来进行操作。但是如果我们需要A组件的状态在其他十个或者…

mongodb,redis,mysql 区别

一、MySQL 关系型数据库。 在不同的引擎上有不同 的存储方式。 查询语句是使用传统的sql语句&#xff0c;拥有较为成熟的体系&#xff0c;成熟度很高。 开源数据库的份额在不断增加&#xff0c;mysql的份额页在持续增长。 缺点就是在海量数据处理的时候效率会显著变慢。 二、Mo…

Linux·从 URL 输入到页面展现到底发生什么?

打开浏览器从输入网址到网页呈现在大家面前&#xff0c;背后到底发生了什么&#xff1f;经历怎么样的一个过程&#xff1f;先给大家来张总体流程图&#xff0c;具体步骤请看下文分解&#xff01; 总体来说分为以下几个过程: DNS 解析:将域名解析成 IP 地址TCP 连接&#xff1a…

学习babylon.js --- [2] 项目工程搭建

本文讲述如何搭建babylonjs的项目工程。 一 准备 首先创建一个目录叫MyProject&#xff0c;然后在这个目录里再创建三个目录&#xff1a;dist&#xff0c;public和src&#xff0c;如下&#xff0c; 接着在src目录里添加一个文件叫app.ts&#xff0c;本文使用typescript&#…

【蓝图】p28-p29按键+鼠标点击实现开关门

p28-p29按键鼠标点击实现开关门 p28&#xff0c;创建门的蓝图类创建一个Actor注意&#xff08;当门的中心点不在边角上时&#xff09; 蓝图三个旋转区别按E键开关门使鼠标点击也可以开门可能遇到的bug问题 p28&#xff0c;创建门的蓝图类 actor和组件的区别、门的轴心点修改 …

【测试开发】测试用例的设计方法

目录 一. 测试用例的基本要素 二. 测试用例的设计方法 1. 测试用例设计的万能公式 水杯测试用例 2. 基于需求的设计方法 邮箱注册测试用例 3. 等价类方法 有效等价类和无效等价类 等价类思想设计测试用例步骤 4. 边界值方法 边界值思想设计测试用例步骤 5. 判定表方法…

Docker——认识Docker 常用命令 Linux中安装docker 常见问题及其解决

目录 引出Docker是啥&#xff1f;Docker是啥&#xff1f;Docker VS 虚拟机1.特性优势2.资源优势 Docker的架构Docker常用命令&#xff08;0&#xff09;docker run&#xff08;1&#xff09;docker ps&#xff08;2&#xff09;docker stop 容器名称&#xff08;3&#xff09;…

DETR (DEtection TRansformer)基于自建数据集开发构建目标检测模型超详细教程

目标检测系列的算法模型可以说是五花八门&#xff0c;不同的系列有不同的理论依据&#xff0c;DETR的亮点在于它是完全端到端的第一个目标检测模型&#xff0c;DETR&#xff08;Detection Transformer&#xff09;是一种基于Transformer的目标检测模型&#xff0c;由Facebook A…
最新文章