《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 ...
随机推荐
- c++ 类的默认八种函数
c++ 类的默认八种函数 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #incl ...
- T9
T9 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission ...
- keepalived中的脑裂
在高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体.动作协调的HA系统,就分裂成为2个独立的个体.由于相互失去了联系,都以为是对方出了故障.两个节点上的HA软件像“裂脑人”一样,争 ...
- Python 读取某个目录下的文件
读取某个目录下的文件,如'/Users/test/test_kmls'目录下有test1.txt.test2.txt. 第一种方法读出的all_files是test1.txt.test2.txt im ...
- Appium python自动化测试系列之日志的收集(十二)
13.1 日志的定义 13.1.1 日志的定义 听到日志这个东西可能有的人莫名其妙,第一次接触就会觉得我们为什么要收集日志,即使要收集日志那么我们需要收集哪些日志,日志的作用是什么等等. 其实日志无 ...
- Java面试常会被问到的经典面试题,学习或者求职,你都要好好掌握
Java现在的热度虽然有所下降,但是,学Java的人依旧很多..Java的岗位也是渗透很多.那么,那些经典的Java知识点,你能看到问题就能说出一二三吗?来一起看看.. 1.JDK和JRE的区别 2. ...
- 一起写框架-Ioc内核容器的实现-基础API的定义(三)
Ioc内核要解决的问题 1.被调用方,在程序启动时就要创建好对象,放在一个容器里面. 2.调用方使用一个接口或类的引用(不用使用new),就可以创建获得对象. 解决这个两个问题的思路 1.定义一个对象 ...
- css定位讲解
定位分三种:相对定位,绝对定位,固定定位; 相对定位:position:relatve; 绝对定位:position:absolute; 固定定位:position:fixed; 一, ...
- oracle数据库管理系统常见的错误(二)
oracle数据库,对于新手来说总会遇到这样的问题: 相信大家都遇到了这样的问题,说实话,我曾经就遇到过这样的问题,但是不好意思问旁边的技术大咖,都有点怀疑人生了,然后自己在网上去查找原因,结果发现, ...
- this和static关键字
this和static关键字 一.关键字this this表示对象自身的引用 this的作用 1.用来区别当前类对象的成员与参数成员 2.用来调用其它构造方法 构造方法: 1.每个类默认情况都有一个默 ...