原文来自 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. mvc4 实现自己的权限验证 仿Authorize与AllowAnonymous原理

    参考文章 :http://www.cosdiv.com/page/M0/S878/878978.html 实现的效果:在控制器上(Controller)验证权限,在动作(Action)上不验证. 用M ...

  2. IdentityServer4 登录使用数据库

    业务场景: IdentityServer4 默认使用TestUser和UserStore,需要模拟和加载所有的用户数据,正式环境肯定不能这样实现,我们想从自己的数据库中读取用户信息,另外,因为 Ide ...

  3. PHP读取数据库表显示到前台

    <?php$username=$_GET['uid']; //获取一个值作为查询条件 $result=$db->query("select * from trip where a ...

  4. CSS实现父元素半透明,子元素不透明

    CSS实现父元素半透明,子元素不透明. 很久以来大家都习惯使用opacity:0.5在新式浏览器里实现半透明,而对IE较旧的版本使用filter:Alpha(opacity=0.5)的滤镜来实现半透明 ...

  5. EasyUI扩展验证

    1.首先在jquery.easyui.min.js下最后插入下面代码 $.extend($.fn.validatebox.defaults.rules, { idcard : {// 验证身份证 va ...

  6. 一起写框架-控制反转(Ioc)概述(二)

    控制反转概述 控制反转(Inversion of Control,英文缩写为IoC),就是将代码的调用的控制权,由调用方转移给被调用方. 如图:修改代码A类的代码,才能将B类的对象换成C类.代码的控制 ...

  7. oracle数据库管理系统常见的错误(二)

    oracle数据库,对于新手来说总会遇到这样的问题: 相信大家都遇到了这样的问题,说实话,我曾经就遇到过这样的问题,但是不好意思问旁边的技术大咖,都有点怀疑人生了,然后自己在网上去查找原因,结果发现, ...

  8. [转载] RED-BLACK(红黑)树的实现TreeMap源码阅读

    转载自http://lxy2330.iteye.com/blog/1664786 由于平衡二叉树与红黑树都是二叉排序树,又红黑树是对平衡二叉树的一种改进实现,所以它的很多思想算法都来源于排序二叉或平衡 ...

  9. python 面对post分页爬虫

    分享一则对于网抓中面对post请求访问的页面或者在分页过程中需要post请求才可以访问的内容! 面的post请求的网址是不可以零参访问网址的,所以我们在网抓的过程中需要给请求传表单数据,下面看一下网页 ...

  10. 一步一步教你用c# entity framework6 连接 sqlite 实现增删改查

    使用entity framework6 连接 SQLite 数据库 前言 很多小型应用程序中,都要使用数据库,而现在比较流行的本地数据库非SQLite莫属. 第一步:前期准备 开发环境:vs2015 ...