原文来自 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))

EmitLogDirect.cs 完整源代码)和(ReceiveLogsDirect.cs 完整源代码

《RabbitMQ Tutorial》译文 第 4 章 路由的更多相关文章

  1. 《RabbitMQ Tutorial》第 1 章 简介

    本文来自英文官网,其示例代码采用了 .NET C# 语言. <RabbitMQ Tutorial>第 1 章 简介(Introduction) RabbitMQ is a message ...

  2. AnguarJS——第10章 路由

    第10章 路由 一个应用是由若个视图组合而成的,根据不同的业务逻辑展示给用户不同的视图,路由则是实现这一功能的关键. 10.1 SPA SPA(Single Page Application)指的是通 ...

  3. 《RabbitMQ Tutorial》译文 第 3 章 发布和订阅

    原文来自 RabbitMQ 英文官网的教程(3.Publish and Subscribe),其示例代码采用了 .NET C# 语言. In the previous tutorial we crea ...

  4. 《RabbitMQ Tutorial》译文 第 2 章 工作队列

    源文来自 RabbitMQ 英文官网的教程(2.Work Queues),其示例代码采用了 .NET C# 语言. In the first tutorial we wrote programs to ...

  5. 《RabbitMQ Tutorial》译文 第 5 章 主题

    原文来自 RabbitMQ 英文官网的教程(5.Topics),其示例代码采用了 .NET C# 语言. In the previous tutorial we improved our loggin ...

  6. 《RabbitMQ Tutorial》译文 第 6 章 远程过程调用(RPC)

    原文来自 RabbitMQ 英文官网的教程(6.Remote procedure call - RPC),其示例代码采用了 .NET C# 语言. In the second tutorial we ...

  7. 《RabbitMQ Tutorial》译文 第 1 章 简介

    原文来自 RabbitMQ 英文官网的教程(1.Introduction),其示例代码采用了 .NET C# 语言. RabbitMQ is a message broker: it accepts ...

  8. 译:4.RabbitMQ Java Client 之 Routing(路由)

    在上篇博文 译:3.RabbitMQ 之Publish/Subscribe(发布和订阅)  我们构建了一个简单的日志系统 我们能够向许多接收者广播日志消息. 在本篇博文中,我们将为其添加一个功能 - ...

  9. RabbitMQ之Topics(多规则路由)

    Exchange中基于direct类型无法基于多种规则进行路由. 例如分析syslog日志,不仅需要基于severity(info/warning/critical/error)进行路由,还需要基于a ...

随机推荐

  1. @RequestBody对象为空,异常Required request body is missing

    1.异常 org.springframework.http.converter.HttpMessageNotReadableException: Required request body is mi ...

  2. 前端菜鸟学习之DOM事件处理

    一.事件处理程序 1.DOM0级事件处理程序:就是将一个函数赋值给一个事件处理程序属性,至今仍为现代所有浏览器所支持,主要得益于其跨浏览器的优势,要使用DOM0级事件 首先要得到操作对象的引用,具体实 ...

  3. IdentityServer4 退出登录后,跳转到原来页面

    IdentityServer4 退出登录后,默认会跳转到Config.Client配置的PostLogoutRedirectUris地址,那我们如何动态的跳转到原来的地址呢?实现很简单,Logout修 ...

  4. Flex 基础语法(一)

    任何一个容器都可以指定为Flex布局. .box{ display: flex; } 行内元素也可以使用Flex布局. .box{ display: inline-flex; } Webkit内核的浏 ...

  5. stack 的入门

    #include "iostream"#include "stack" using namespace std; void main12(){ stack &l ...

  6. 线上Mysql数据库崩溃事故的原因和处理

    前文提要 承接前文<一次线上Mysql数据库崩溃事故的记录>,在文章中讲到了一次线上数据库崩溃的事件记录,建议两篇文章结合在一起看,不至于摸不着头脑. 由于时间原因,其中只讲了当时的一些经 ...

  7. js滚动加载小插件

    本文实例讲述了jquery滚动加载数据的方法.分享给大家供大家参考.具体分析如下: 少废话直接上代码!!!粗暴,直接,干脆 0//lk-2017-05-04 1(function($, win) { ...

  8. gcc调试 学习1

    gdb进入调试 b 6 在第6行设置断点 d 2 删除num为2的断点 info b 查看断点 run 运行 n 执行到断点1 s 如果下一条是函数就进入函数 n 继续执行 print i  输出i的 ...

  9. mac环境下支持PHP调试工具xdebug,不需要建项目server

    先让php支持xdebug 方式一: https://xdebug.org/download.php 下载相应的xdebug  可以到http://xdebug.org/wizard.php 把php ...

  10. Openstack的打包方法

    使用setup.cfg和setup.py进行管理 1.setup.py文件内容 # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO ...