RabbitMQ 官方NET教程(五)【Topic】
在上一个教程中,我们改进了我们的日志记录系统。我们使用direct
类型转发器,使得接收者有能力进行选择性的接收日志,,而非fanout
那样,只能够无脑的转发
虽然使用direct
类型改进了我们的系统,但它仍然存在一些局限性 - 它不能够基于多重条件进行路由选择。
在我们的日志记录系统中,我们可能不仅要根据严重性订阅日志,还可以基于发出日志的源进行订阅。您可能会从unix工具syslog 中了解此概念,该工具根据严重性(info / warn / crit ...
)和设备(auth / cron / kern ...
)转发日志。
这将给我们带来很大的灵活性 - 我们可能想要订阅来自cron
的严重错误,也可以听kern
的所有日志。
为了在我们的系统中实现上述的需求,我们需要学习稍微复杂的主题类型的转发器(topic exchange)
主题转发(Topic Exchange)
发往主题类型的转发器的消息不能随意的设置选择键(routing_key) - 它必须是由点分隔的单词列表。这些单词可以是任何东西,但通常它们指定与消息相关联的一些功能。几个有效的路由密钥示例:stock.usd.nyse
,nyse.vmw
,quick.orange.rabbit
。路由密钥中可以有任意多的单词,最多可达255个字节。
绑定键也必须是相同的形式。主题类型的转发器背后的逻辑和直接类型的转发器很类似:一个附带特殊的选择键将会被转发到绑定键与之匹配的队列中。需要注意的是:关于绑定键有两种特殊的情况。:
*(星)可以替代一个单词。
#(哈希)可以替换零个或多个单词。
在一个例子中最简单的解释一下:
在这个例子中,我们将发送所有描述动物的消息。消息会附加一个选择键包含将使用由三个单词标识符(两个点隔开)。第一个单词标识符描述速度,第二个单词标识符描述动物的颜色,和第三个单词标识符描述动物的物种:<speed>.<color>.<species>
。
我们创建了三个绑定:Q1
绑定键*.orange.*
和Q2
与*.*.rabbit
和lazy.#
绑定。
这些绑定可以总结为:
Q1对所有的橙色动物感兴趣。
Q2想听听有关兔子的一切,以及关于懒惰动物的一切。
一个附带quick.orange.rabbit的选择键的消息将会被转发到两个队列。附带lazy.orange.elephant
的消息也会被转发到两个队列。另一方面,quick.orange.fox
只会转到Q1,而lazy.brown.fox
只能被转发到Q2。 lazy.pink.rabbit
虽然与两个绑定键匹配,但是也只会被转发到Q2一次。 quick.brown.fox
不能与任何绑定键匹配,因此它将被丢弃。
如果我们违法我们的约定,发送一个或者四个标识符的选择键,类似:orange
,quick.orange.male.rabbit
,这些选择键不能与任何绑定键匹配,所以消息将会被丢弃。
另一方面,lazy.orange.male.rabbit
虽然是四个标识符,也可以与lazy.#
匹配,从而转发至Q2。
Topic exchange
主题类型的转发器非常强大,可以实现其他类型的转发器。
当队列与`#`(哈希)绑定键绑定时,它将接收所有消息,而不管路由键,类似`fanout`类型转发器。
当特殊字符`*`(星号)和`#`(哈希)在绑定中不被使用时,主题转发器将类似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,
noAck: true,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}
运行以下示例:
收到所有的日志:
cd ReceiveLogsTopic
dotnet run "#"
从设备kern
接收所有日志:
cd ReceiveLogsTopic
dotnet run "kern.*"
或者如果您只想收到关于critical
的日志:
ReceiveLogsTopic.exe "*.critical"
您可以创建多个绑定:
cd ReceiveLogsTopic
dotnet run "kern.*" "*.critical"
并使用选择键kern.critical
类型发出日志:
cd EmitLogTopic
dotnet run "kern.critical" "A critical kernel error"
RabbitMQ 官方NET教程(五)【Topic】的更多相关文章
- 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange
如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...
- RabbitMQ官方教程五 Topic(GOLANG语言实现)
在上一教程中,我们改进了日志记录系统. 我们没有使用只能进行虚拟广播的fanout交换器,而是使用直接交换器,并有可能选择性地接收日志. 尽管使用直接交换改进了我们的系统,但它仍然存在局限性-它不能基 ...
- RabbitMQ Go客户端教程5——topic
本文翻译自RabbitMQ官网的Go语言客户端系列教程,本文首发于我的个人博客:liwenzhou.com,教程共分为六篇,本文是第五篇--topic. 这些教程涵盖了使用RabbitMQ创建消息传递 ...
- RabbitMQ 官方NET教程(三)【发布/订阅】
上一篇博客中,我们实现了工作队列,并且我们的工作队列中的一个任务只会发给一个工作者,除非某个工作者未完成任务意外被杀死,会转发给另外的工作者.在这部分中,我们会做一些完全不同的事情 - 我们会向多个消 ...
- RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange
1.topic类型的Exchange 我们之前说过Topic类型的Exchange是direct类型的模糊查询模式,可以通过routkey来实现模糊消费message,topic的模糊匹配有两种模式: ...
- RabbitMQ 官方NET教程(六)【RPC】
在第二个教程中,我们学习了如何使用Work Queues在多个工作者之间分配耗时的任务. 但是如果我们需要在远程计算机上运行功能并等待结果怎么办? 那是一个不同的模式. 此模式通常称为远程过程调用或R ...
- RabbitMQ 官方NET教程(四)【路由选择】
在上一个教程中,我们构建了一个简单的日志记录系统. 我们能够广播日志消息给所有你的接收者. 在本教程中,我们将为其添加一个功能 - 我们将让日志接收者可以仅订阅一部分消息. 例如,我们将能够仅将关键的 ...
- RabbitMQ 官方NET教程(二)【工作队列】
这篇中我们将会创建一个工作队列用来在工作者(consumer)间分发耗时任务. 工作队列的主要任务是:避免立刻执行资源密集型任务和避免必须等待其完成.相反地,我们进行任务调度:我们把任务封装为消息发送 ...
- RabbitMQ 官方NET教程(一)【介绍】
本教程假定RabbitMQ已在标准端口(5672)上的localhost上安装并运行.如果使用不同的主机,端口或凭据,连接设置将需要调整. RabbitMQ是一个消息代理:它接受并转发消息. 您可以将 ...
随机推荐
- 【转载】使用IntelliJ IDEA 配置Maven(入门)
1. 下载Maven 官方地址:http://maven.apache.org/download.cgi 解压并新建一个本地仓库文件夹 2.配置本地仓库路径 3.配置maven环境变量 ...
- bat 读取当前目录指定文件信息并拼接
bat 读取指定文件的信息并拼接成指定格式
- STM32学习笔记:读写内部Flash(介绍+附代码)
一.介绍 首先我们需要了解一个内存映射: stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同. RAM起 ...
- wx微信小程序
俩三行时: ==========
- 如何拿CSDN博客上的原图
比如带水印的地址: http://img.blog.csdn.net/20140408122234546?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdT ...
- Spring MVC-视图解析器(View Resolverr)-资源包视图解析器(Resource Bundle View Resolver)示例(转载实践)
以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_resourcebundleviewresolver.htm 说明:示例基于Spr ...
- 一次MySQL(INNODB存储引擎) 死锁捉虫记
前言 任何系统不管在什么阶段都需要关注生产环境错误日志,最近几个月内,发现偶尔会出现数据库死锁情况.以前碰到的数据库类错误大部分是SQL语法造成的错误,来到新东家之后才第一次碰到死锁情况,以前是搞游戏 ...
- supervisord进程管理工具小结
前言 昨天临近下班,发现业务队列处理不及时,正好想到不久之前,上了一个新功能:通过队列异步转发微信消息.可能是消息太多了处理不过来,没怎么多想,处理不过来了,多增加处理进程就可以了,后来发现自己so ...
- 【线段树I:母题】hdu 1166 敌兵布阵
[线段树I:母题]hdu 1166 敌兵布阵 题目链接:hdu 1166 敌兵布阵 题目大意 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又開始忙乎了.A国在海 ...
- vim中凝视多行python代码
在vim中凝视多行python代码比較麻烦,主要由下面几种方法: (1)将须要凝视的代码以文档字符串的形式呈现 (2)将须要凝视的代码以函数的形式呈现 (3)使用vim自身快捷键 我们主要使用第三种方 ...