RabbitMQ四:Routing
上一篇博客构建了一个简单的日志系统,能够像多个接受者广播日志信息。
本文将添加一个功能,用以说明RabbitMQ
中的Routing
:
只能订阅一部分消息,例如,我们只能将错误信息写入日志文件(以节省磁盘空间),同时在控制台打印所有日志消息。
直接交换
上一批文章中的日志记录系统向所有消费者广播消息,我们现在希望扩展它以允许根据消息的严重性过滤消息。例如,我们仅将严重错误的日志消息写入磁盘,警告或者信息日志则不写入。
我们将使用直接交换,直接交换背后的路由算法如下:消息进入队列,其绑定密钥与消息的路由密钥完全匹配。
如图,orange绑定Q1队列,black和green绑定Q2队列,使用路由密钥orange发布到交换机的消息将被路由到Q1。green和black则被路由到Q2。除此之外的其他消息将被丢弃。
多个绑定
使用相同的绑定密钥绑定多个队列是完全合法的。例子中,我们可以在X和Q1之间添加black的绑定。在这种情况下,直接交换将表现得像扇出一样,并将消息广播到所有匹配的队列。路由密钥为black的消息将传送到Q1和Q2。
发送日志
创建一个交换机:
channel.ExchangeDeclare(exchange:“direct_logs”,type:“direct”);
准备好发送消息:
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_logs", routingKey: severity, basicProperties: null, body: body);
订阅
接收消息将像上一篇文章一样工作,但有一个例外:我们将为我们感兴趣的每个严重性创建一个新的绑定。
var queueName = channel.QueueDeclare().QueueName;
foreach (var severity in args)
{
channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: severity);
}
示例
示例代码绑定规则如下:
代码:
EmitLogDirect
class EmitLogDirect
{
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "127.0.0.1" };
using (var conncetion = factory.CreateConnection())
using (var channel = conncetion.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 {severity}:{message}");
}
Console.WriteLine(" Press [enter] to exit");
Console.ReadLine();
}
}
ReceiveLogsDirect
class ReceiveLogsDirect
{
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "127.0.0.1" };
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.WriteLine($"Usage:{Environment.GetCommandLineArgs()[0]} [info] [warning] [error]");
Console.WriteLine(" Press [entet] 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 message.");
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 {routingKey}:{message}");
};
channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
Console.ReadLine();
}
}
}
效果如下: