《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 ...
随机推荐
- Restaurant
Restaurant Time Limit:4000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Submit ...
- 关于狄克斯特拉算法(dijkstra)总结
1,2,4是四个定点其他的是距离,从2到4最直接的就是2-4,但是不是最近的,需要舒展一下2-1-4,这样只有8.所以才是最短的.这个过程就是狄克斯特拉算法.下面进入正题: 我们这里定义图的编号为 ...
- Sqoop的安装部署
在root的用户下 1):前提 安装JDK环境 2):前提 安装Hadoop和Hive客户端环境,如果需要导出到HBase则需要安装HBase客户端 3):下载sqoop : 命令: wget htt ...
- Flexbox 布局教程
Flex 布局是什么? Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为 Flex 布局. 使用 fle ...
- 【Win 10 应用开发】UI Composition 札记(四):绘制图形
使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码. 先来说说如何获取 Win 2D 组件.很简单,创建 UWP 应用项目后,你打开“解 ...
- 团队工作准则&贡献分配规则
团队工作准则&贡献分配规则 NewTeam 2017/10/24 v1.0 工作准则及内容 全体成员 所有成员在接受任务时应结合自身情况考虑,如果认为任务内容或时间有不合理之处应当立即提出修改 ...
- Erlang Concurrent 并发进阶
写在前面的话 本文来源于官方教程 Erlang -- Concurrent Programming.虽然没有逻辑上的关系,但建议在掌握了Erlang入门系列教程的一些前置知识后继续阅读. 之前我是逐小 ...
- Unity学习资料
前段时间刚简单接触下Spring.net,刚会简单注入,最近接手一项目确是用的Unity,网上找了一些很好的教程资料 算是入门了,高手已经写的很好了,我就转个链接吧: Unity V3 初步使用 —— ...
- 一次触摸,Android到底干了啥
WeTest 导读 当我们在写带有UI的程序的时候,如果想获取输入事件,仅仅是写一个回调函数,比如(onKeyEvent,onTouchEvent-.),输入事件有可能来自按键的,来自触摸的,也有来自 ...
- 解决mssql localdb 中文乱码问题
使用以下查询语句即可. alter database "E:\.Net Core\Database\hm.mdf" set single_user with rollback im ...