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

In the previous tutorial we built a simple logging system. We were able to broadcast log messages to many receivers.
在之前的教程中,我们构建了一个简单的日志系统,我们可以广播日志消息给众多的接收人。
In this tutorial we're going to add a feature to it - we're going to make it possible to subscribe only to a subset of the messages. For example, we will be able to direct only critical error messages to the log file (to save disk space), while still being able to print all of the log messages on the console.
在本教程中我们即将为日志系统添加一个特性 - 使其可以只订阅消息的一个子集。比如,我们只会直接将严重错误消息写入到日志文件(即保存到磁盘空间),与此同时还会把所有的日志消息打印到控制台。
Bindings
绑定
In previous examples we were already creating bindings. You may recall code like:
在之前的示例中我们已经创建过绑定,你可能会回忆起类似的代码:
channel.QueueBind(queue: queueName,
exchange: "logs",
routingKey: "");
A binding is a relationship between an exchange and a queue. This can be simply read as: the queue is interested in messages from this exchange.
绑定就是交换机和队列之间的一种关系,可以简单地理解为:某队列对来自该交换机的消息感兴趣。
Bindings can take an extra routingKey parameter. To avoid the confusion with a BasicPublish parameter we're going to call it a binding key. This is how we could create a binding with a key:
绑定可以使用一个额外的 routingKey 参数,为避免与 BasicPublish 参数相混淆我们将其称呼为“绑定键”,如下便是如何采用该键来创建一个绑定:
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: "black");
The meaning of a binding key depends on the exchange type. The fanout exchanges, which we used previously, simply ignored its value.
“绑定键”的含义取决于交换机类型,像我们之前使用过的 fanout 型交换机,简单起键其值在这里就忽略了。(fanout 型交换机是无差别广播到所有队列,即使为 routingKey 命名也没有意义)
Direct exchange
直接型交换机
Our logging system from the previous tutorial broadcasts all messages to all consumers. We want to extend that to allow filtering messages based on their severity.
For example we may want the script which is writing log messages to the disk to only receive critical errors, and not waste disk space on warning or info log messages.
在我们之前的教程中,日志系统会广播所有的消息给所有的消费者。我们希望基于系统所面临的压力来做一些诸如允许过滤消息这样的扩充。
比如我们可能希望只接收严重错误的日志消息脚本,然后将其写入磁盘,而不要在警告型或提示型日志消息方面浪费磁盘空间。
We were using a fanout exchange, which doesn't give us much flexibility - it's only capable of mindless broadcasting.
我们一直在使用 fanout 型交换机,但它给予不了我们足够的灵活性 - 它仅仅适用于无差别(无脑式)的广播。
We will use a direct exchange instead. The routing algorithm behind a direct exchange is simple - a message goes to the queues whose binding key exactly matches the routing key of the message.
好在我们可以使用 direct 型交换机,其背后的路由算法很简单 - 即消息会流向其绑定键恰好与路由键相匹配的队列。
To illustrate that, consider the following setup:
为说明这个,可以考虑接下来的设置:

In this setup, we can see the direct exchange X with two queues bound to it. The first queue is bound with binding key orange, and the second has two bindings, one with binding key black and the other one with green.
在这个设置中,我们可以看到符号为 X 的 direct 型交换机有两个队列关联 到它。第一个队列通过“绑定键” orange 来关联,第二个队列则有两个绑定,一个基于 black “绑定键”,另一个基于 green “绑定键”。
In such a setup a message published to the exchange with a routing key orange will be routed to queue Q1. Messages with a routing key of black or green will go to Q2. All other messages will be discarded.
在这样一番设置中,发布到基于 orange 路由键绑定的消息将会被路由到 Q1 队列,而基于 black 或者 green 路由键的消息则去往 Q2 队列,而其他所有的消息将会被丢弃。
Multiple bindings
多重绑定

It is perfectly legal to bind multiple queues with the same binding key. In our example we could add a binding between X and Q1 with binding key black. In that case, the direct exchange will behave like fanout and will broadcast the message to all the matching queues. A message with routing key black will be delivered to both Q1 and Q2.
采用相同的“绑定键”来绑定多个队列是完全合法的。在我们的示例中,可以基于 black “绑定键”来添加一个 X 和 Q1 之间的绑定。如此,direct 型交换机将表现得与 fanout 型相像,并且会把消息广播给所有匹配的队列。如此,基于 black “路由键”的消息将会被递送到 Q1 和 Q2 两个队列。
Emitting logs
发出日志
We'll use this model for our logging system. Instead of fanout we'll send messages to a direct exchange. We will supply the log severity as a routing key. That way the receiving script will be able to select the severity it wants to receive. Let's focus on emitting logs first.
我们将为日志系统使用以上模型,我们会在发送消息时使用 direct 型交换机,而不是 fanout 型。我们会基于日志的严重性作为路由键,这样的话接收端脚本将可以选择它期望接收的严重性。让我们首先聚焦在发送日志方面。
As always, we need to create an exchange first:
一如既往,我们需要首先创建一个交换机:
channel.ExchangeDeclare(exchange: "direct_logs", type: "direct");
And we're ready to send a message:
接着我们准备好发送消息:
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_logs",
routingKey: severity,
basicProperties: null,
body: body);
To simplify things we will assume that 'severity' can be one of 'info', 'warning', 'error'.
为简单起键,我们假定“severity”变量指的就是“info”、“warning”以及“error”中的一种。
Subscribing
订阅
Receiving messages will work just like in the previous tutorial, with one exception - we're going to create a new binding for each severity we're interested in.
就像之前教程一样,接收消息这一块都运行得很好,唯独有一处不同 -- 那就是我们 为自己所感兴趣的(日志的)每一种严重性创建一个新的绑定。
var queueName = channel.QueueDeclare().QueueName;
foreach(var severity in args)
{
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: severity);
}
Putting it all together
融合一起

The code for EmitLogDirect.cs class:
EmitLogDirect.cs 类文件代码:
using System;
using System.Linq;
using RabbitMQ.Client;
using System.Text;
class EmitLogDirect
{
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: "direct_logs",
type: "direct");
var severity = (args.Length > 0) ? args[0] : "info";
var message = (args.Length > 1)
? string.Join(" ", args.Skip( 1 ).ToArray())
: "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_logs",
routingKey: severity,
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent '{0}':'{1}'", severity, message);
}
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
The code for ReceiveLogsDirect.cs:
ReceiveLogsDirect.cs 类文件代码:
using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
class ReceiveLogsDirect
{
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: "direct_logs",
type: "direct");
var queueName = channel.QueueDeclare().QueueName;
if(args.Length < 1)
{
Console.Error.WriteLine("Usage: {0} [info] [warning] [error]",
Environment.GetCommandLineArgs()[0]);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
Environment.ExitCode = 1;
return;
}
foreach(var severity in args)
{
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: severity);
}
Console.WriteLine(" [*] Waiting for messages.");
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();
}
}
}
Create projects as usual (see tutorial one for advice).
像往常一样创建工程(看看教程第一章的建议)
If you want to save only 'warning' and 'error' (and not 'info') log messages to a file, just open a console and type:
如果你只想保存“warning”和“error”(不包括“info”)类型的日志消息到文件,只需打开控制台并输入:
cd ReceiveLogsDirect
dotnet run warning error > logs_from_rabbit.log
If you'd like to see all the log messages on your screen, open a new terminal and do:
如果你想在显示屏上看到所有的日志消息,可以打开新的终端并输入:
cd ReceiveLogsDirect
dotnet run info warning error
# => [*] Waiting for logs. To exit press CTRL+C
And, for example, to emit an error log message just type:
比如,为了产生一个 error 级别的日志消息只需输入:
cd EmitLogDirect
dotnet run error "Run. Run. Or it will explode."
# => [x] Sent 'error':'Run. Run. Or it will explode.'
(Full source code for (EmitLogDirect.cs source) and (ReceiveLogsDirect.cs source))
《RabbitMQ Tutorial》译文 第 4 章 路由的更多相关文章
- 《RabbitMQ Tutorial》第 1 章 简介
本文来自英文官网,其示例代码采用了 .NET C# 语言. <RabbitMQ Tutorial>第 1 章 简介(Introduction) RabbitMQ is a message ...
- AnguarJS——第10章 路由
第10章 路由 一个应用是由若个视图组合而成的,根据不同的业务逻辑展示给用户不同的视图,路由则是实现这一功能的关键. 10.1 SPA SPA(Single Page Application)指的是通 ...
- 《RabbitMQ Tutorial》译文 第 3 章 发布和订阅
原文来自 RabbitMQ 英文官网的教程(3.Publish and Subscribe),其示例代码采用了 .NET C# 语言. In the previous tutorial we crea ...
- 《RabbitMQ Tutorial》译文 第 2 章 工作队列
源文来自 RabbitMQ 英文官网的教程(2.Work Queues),其示例代码采用了 .NET C# 语言. In the first tutorial we wrote programs to ...
- 《RabbitMQ Tutorial》译文 第 5 章 主题
原文来自 RabbitMQ 英文官网的教程(5.Topics),其示例代码采用了 .NET C# 语言. In the previous tutorial we improved our loggin ...
- 《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 ...
- 译:4.RabbitMQ Java Client 之 Routing(路由)
在上篇博文 译:3.RabbitMQ 之Publish/Subscribe(发布和订阅) 我们构建了一个简单的日志系统 我们能够向许多接收者广播日志消息. 在本篇博文中,我们将为其添加一个功能 - ...
- RabbitMQ之Topics(多规则路由)
Exchange中基于direct类型无法基于多种规则进行路由. 例如分析syslog日志,不仅需要基于severity(info/warning/critical/error)进行路由,还需要基于a ...
随机推荐
- PyQt中对RadioButton分组
我们知道在同一widget组件中的radio button有排他属性,为了在一个窗口中显示多组radio button,我们需要对其分组. 通常有两种选择,一种是BoxGroup,另一种是Button ...
- trait与policy模板应用简单示例
trait与policy模板应用简单示例 accumtraits.hpp // 累加算法模板的trait // 累加算法模板的trait #ifndef ACCUMTRAITS_HPP #define ...
- Problem M
Problem Description Accounting for Computer Machinists (ACM) has sufferred from the Y2K bug and lost ...
- Interviewe
Interviewe Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Su ...
- 我的Spring学习记录(五)
在我的Spring学习记录(四)中使用了注解的方式对前面三篇做了总结.而这次,使用了用户登录及注册来对于本人前面四篇做一个应用案例,希望通过这个来对于我们的Spring的使用有一定的了解. 1. 程序 ...
- vue 集成 axios 发送post请求 payload导致后台无法接收到数据问题
vue 集成axios之后,发送的post请求默认为payload 方式. 如果想改为正常的方式,需要增加headers头,并且将发送是数据json格式改为 querystring的方式. 安装依赖 ...
- 谷歌浏览器Chrome播放rtsp视频流解决方案
找半天,HTML5的可以支持RTMP 但是无法播放RTSP,flash也止步于RTMP,最后同事推荐了个开源的好东东 VLC ,请教谷歌大神之后,这货果然可以用来让各浏览器(IE activex方式, ...
- SQL注入详解
SQL是一种将SQL代码添加到输入参数中,传递到SQL服务器解析并执行的一种攻击手段 产生的原因 web开发人员无法保证所有输入都已经安全过滤 攻击者利用发送给SQL服务器的输入数据,构造可执行的SQ ...
- 机器学习数学|Taylor展开式与拟牛顿
机器学习中的数学 觉得有用的话,欢迎一起讨论相互学习~Follow Me 原创文章,如需转载请保留出处 本博客为七月在线邹博老师机器学习数学课程学习笔记 Taylor 展式与拟牛顿 索引 taylor ...
- javascript 中parseInt 的用法
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8 ...