《RabbitMQ Tutorial》译文 第 5 章 主题
原文来自 RabbitMQ 英文官网的教程(5.Topics),其示例代码采用了 .NET C# 语言。

In the previous tutorial we improved our logging system. Instead of using a fanout exchange only capable of dummy broadcasting, we used a direct one, and gained a possibility of selectively receiving the logs.
在之前的教程中,我们改进了日志系统。比起只能够单一广播的 fanout 型交换机,我们现在采用了 direct 型,从而获得了选择性接收日志的可能性。
Although using the direct exchange improved our system, it still has limitations - it can't do routing based on multiple criteria.
尽管使用 direct 型交换机对系统有所改进,但仍然有其局限性 - 即在多重条件下没办法进行路由。
In our logging system we might want to subscribe to not only logs based on severity, but also based on the source which emitted the log. You might know this concept from the syslog unix tool, which routes logs based on both severity (info/warn/crit...) and facility (auth/cron/kern...).
在该日志系统中,我们可能希望不仅仅订阅基于严重性(这一项指标)的日志,也希望能基于产生日志的源头。你大概会知道这个概念来自于 syslog unix 工具,它可以针对严重性(info/warn/crit...)和设备(auth/cron/kern...)进行路由。
That would give us a lot of flexibility - we may want to listen to just critical errors coming from 'cron' but also all logs from 'kern'.
这便给了我们许多灵活性 - 我们可以做到监听“cron”类型的严重错误,以及所有来自于“kern”设备的日志。
To implement that in our logging system we need to learn about a more complex topic exchange.
为了在我们的日志系统中实现上述功能,我们需要学习更为复杂的话题(Topic)交换机。
Topic exchange
话题交换机
Messages sent to a topic exchange can't have an arbitrary routing_key - it must be a list of words, delimited by dots. The words can be anything, but usually they specify some features connected to the message. A few valid routing key examples: "stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit". There can be as many words in the routing key as you like, up to the limit of 255 bytes.
发送至 topic 型交换机的消息已不能携带任意的 routing_key - 而必须是一个字符串列表,并基于小数点来分隔。
The binding key must also be in the same form. The logic behind the topic exchange is similar to a direct one - a message sent with a particular routing key will be delivered to all the queues that are bound with a matching binding key. However there are two important special cases for binding keys:
- * (star) can substitute for exactly one word.
- # (hash) can substitute for zero or more words.
“绑定键”也必须是相同的格式。topic 型交换机背后的逻辑与 direct 型交换机相似 - 采用指定 routing key 所发送的消息将会被递送到与 binding key 相匹配的队列中,然而针对 binding key 有两个非常重要且特殊的情形:
- * (星号)可以替代一个明确的字符串。
- # (哈希,井号)可以替代 0 至多个字符串。
It's easiest to explain this in an example:
在示例中可以很容易的对其解释:

In this example, we're going to send messages which all describe animals. The messages will be sent with a routing key that consists of three words (two dots). The first word in the routing key will describe speed, second a colour and third a species: "..".
在这个示例中,我们打算发送用来描述动物的消息,它是基于三个字符串(包含两个小数点)组成的 routing key,其第一个字符串将用来描述速度,第二个是颜色,第三个是物种,如下:“<速度>.<颜色>.<物种>”。
We created three bindings: Q1 is bound with binding key ".orange." and Q2 with "..rabbit" and "lazy.#".
我们创建了三个绑定,队列 Q1 将关联到绑定键“*.orange.*”,队列 Q2 则关联到“*.*.rabbit”和“lazy.#”。
These bindings can be summarised as:
- Q1 is interested in all the orange animals.
- Q2 wants to hear everything about rabbits, and everything about lazy animals.
这些绑定可以概括为:
- 队列 Q1 对所有桔黄色(orange)的动物感兴趣。
- 队列 Q2 期望监听到所有 rabbit 后缀,以及所有 lazy 前缀的动物。
A message with a routing key set to "quick.orange.rabbit" will be delivered to both queues. Message "lazy.orange.elephant" also will go to both of them. On the other hand "quick.orange.fox" will only go to the first queue, and "lazy.brown.fox" only to the second. "lazy.pink.rabbit" will be delivered to the second queue only once, even though it matches two bindings. "quick.brown.fox" doesn't match any binding so it will be discarded.
routing key 设置为"quick.orange.rabbit"的消息将会被递送到两个队列。消息"lazy.orange.elephant"同样也会去往两个队列。另一方面,"quick.orange.fox"将只会去往第一个队列,"lazy.brown.fox"则只会去第二个队列。"lazy.pink.rabbit",尽管它匹配了两个绑定,但只会被递送到第二个队列一次(而不会是两次)。"quick.brown.fox"则不匹配任何绑定,所以将会被丢弃。
What happens if we break our contract and send a message with one or four words, like "orange" or "quick.orange.male.rabbit"? Well, these messages won't match any bindings and will be lost.
如果我们打破约定将会发生什么呢?比如发送一个字符串或者四个字符串,类似于“orange”或者“quick.orange.male.rabbit”。
On the other hand "lazy.orange.male.rabbit", even though it has four words, will match the last binding and will be delivered to the second queue.
另一方面像“lazy.orange.male.rabbit”,即使它有四个字符串,但仍然会匹配最后一个绑定(lazy.#)并被递送到第二个队列。
Topic exchange
话题交换机
Topic exchange is powerful and can behave like other exchanges.
话题(Topic)交换机很强大,它可以表现得类似其他交换机。
When a queue is bound with "#" (hash) binding key - it will receive all the messages, regardless of the routing key - like in fanout exchange.
当一个队列采用"#"作为绑定键时,它将接收到所有的消息而忽略掉路由键,这就像是 fanout 型交换机一样。
When special characters "*" (star) and "#" (hash) aren't used in bindings, the topic exchange will behave just like a direct one.
当特殊字符"*" (星号) and "#" (哈希,井号)都没有应用到绑定中时,topic 型交换机将表现得与 direct 型一样。
Putting it all together
融合一起
We're going to use a topic exchange in our logging system. We'll start off with a working assumption that the routing keys of logs will have two words: ".".
我们即将在日志系统中使用 topic 型交换机,首先从一个假定的工作前替起步,即拟定日志的路由键为两个字符串:"."
The code is almost the same as in the previous tutorial.
其代码与之前教程几乎相同。
The code for EmitLogTopic.cs:
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);
}
}
}
The code for ReceiveLogsTopic.cs:
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();
}
}
}
Run the following examples:
运行示例:
To receive all the logs:
接收所有的日志:
cd ReceiveLogsTopic
dotnet run "#"
To receive all logs from the facility "kern":
只接收来自“kern”设备的日志:
cd ReceiveLogsTopic
dotnet run "kern.*"
Or if you want to hear only about "critical" logs:
或者你只想关心“critical”级别的日志:
ReceiveLogsTopic.exe "*.critical"
You can create multiple bindings:
你可以创建多重绑定:
cd ReceiveLogsTopic
dotnet run "kern.*" "*.critical"
And to emit a log with a routing key "kern.critical" type:
基于路由键“kern.critical”来产生日志,可以输入:
cd EmitLogTopic
dotnet run "kern.critical" "A critical kernel error"
Have fun playing with these programs. Note that the code doesn't make any assumption about the routing or binding keys, you may want to play with more than two routing key parameters.
程序执行起来还是很令人愉快的,要注意的是,这些代码并没有针对路由键或者绑定键做任何预设 ,你可能会需要用到超出两个以上的路由键参数。
(Full source code for EmitLogTopic.cs and ReceiveLogsTopic.cs)
( EmitLogTopic.cs 和 ReceiveLogsTopic.cs 完整代码)
《RabbitMQ Tutorial》译文 第 5 章 主题的更多相关文章
- 《RabbitMQ Tutorial》第 1 章 简介
本文来自英文官网,其示例代码采用了 .NET C# 语言. <RabbitMQ Tutorial>第 1 章 简介(Introduction) RabbitMQ is a message ...
- Ext JS 6学习文档-第8章-主题和响应式设计
Ext JS 6学习文档-第8章-主题和响应式设计 主题和响应式设计 本章重点在 ExtJS 应用的主题和响应式设计.主要有以下几点内容: SASS 介绍和入门 主题 响应式设计 SASS 介绍和入门 ...
- 《RabbitMQ Tutorial》译文 第 2 章 工作队列
源文来自 RabbitMQ 英文官网的教程(2.Work Queues),其示例代码采用了 .NET C# 语言. In the first tutorial we wrote programs to ...
- 《RabbitMQ Tutorial》译文 第 3 章 发布和订阅
原文来自 RabbitMQ 英文官网的教程(3.Publish and Subscribe),其示例代码采用了 .NET C# 语言. In the previous tutorial we crea ...
- 《RabbitMQ Tutorial》译文 第 4 章 路由
原文来自 RabbitMQ 英文官网的教程(4.Routing),其示例代码采用了 .NET C# 语言. In the previous tutorial we built a simple log ...
- 《RabbitMQ Tutorial》译文 第 6 章 远程过程调用(RPC)
原文来自 RabbitMQ 英文官网的教程(6.Remote procedure call - RPC),其示例代码采用了 .NET C# 语言. In the second tutorial we ...
- 《RabbitMQ Tutorial》译文 第 1 章 简介
原文来自 RabbitMQ 英文官网的教程(1.Introduction),其示例代码采用了 .NET C# 语言. RabbitMQ is a message broker: it accepts ...
- 译:5.RabbitMQ Java Client 之 Topics (主题)
在 上篇博文 译:4.RabbitMQ 之Routing(路由) 中,我们改进了日志系统. 我们使用的是direct(直接交换),而不是使用只能进行虚拟广播的 fanout(扇出交换) ,并且有可能选 ...
- RabbitMQ 消息队列 入门 第二章(交换类型fanout)
1.安装完 RabbitMQ 之后,我们可以点击 http://localhost:15672/#/ 默认账号:guest 密码: guest 在这上面我们可以查看执行情况.管理连接.管理队列 ...
随机推荐
- A计划(双层bfs)
A计划 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissio ...
- 使用TP5创建一个REST API
原文在这里 : http://hmw.iteye.com/blog/1190827 tp自带的api,get请求接口 /** * 显示资源列表 * * @return \think\Response ...
- 「JavaScript」同步、异步、回调执行顺序之经典闭包setTimeout分析
聊聊同步.异步和回调 同步,异步,回调,我们傻傻分不清楚, 有一天,你找到公司刚来的程序员小T,跟他说:“我们要加个需求,你放下手里的事情优先支持,我会一直等你做完再离开”.小T微笑着答应了,眼角却滑 ...
- Windows系统安装MySQL
在Windows中安装mysql不够幸运的话,会遇到相当多的坑,当然这也算是一种财富吧,让自己碰到问题去查找解决方案.有时候不是一时半会就可以解决的.有同学说过安装mysql安装两天还没有装上.不用担 ...
- 如何用 Graylog 管理日志?- 每天5分钟玩转 Docker 容器技术(93)
上一节已经部署好了 Graylog,现在学习如何用它来管理日志. 首先启动测试容器. docker run -d \ --log-driver=gelf \ --log-opt gelf-addres ...
- 一、VueJs 填坑日记之基础概念知识解释
概述在最开始听说vuejs这个词是在2016年,当时天真的认为自己是个后端开发工程师不需要学习太多的前端知识,不过紧接着在2017年在公司就用到了vuejs.对于初学者(尤其是干后端的初学者)来说,刚 ...
- maven---settings.xml配置
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...
- Tomcat部署项目乱码问题总结
打包好的war包放在tomcat下,有时会出现中文乱码的情况.首先应当确定项目的编码格式,tomcat的编码格式,以及cmd命令行的编码格式. 项目编码 将要输出到控制台或日志的字符串转为UTF-8 ...
- Socket网络编程之概述理解
今天主要讲讲什么是socket网络编程 socketde 英文原义是"孔"或者"插座".是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机 ...
- word,excel,ppt转Pdf,Pdf转Swf,通过flexpaper+swftools实现在线预览
其实这是我好几年前的项目,现在再用这种方式我也不建议了,毕竟未来flash慢慢会淘汰,此方式也是因为目测大部分人都装了flash,才这么做的,但是页面展示效果也不好.其实还是考虑收费的控件,毕竟收费的 ...