.NET 下 RabbitMQ 队列、死信队列、延时队列及小应用

开发 前端
RabbitMQ 提供了强大的消息队列功能,在 .NET 应用程序中,我们可以利用其队列、死信队列、延时队列等特性,实现异步通信、任务调度、日志记录。​

引言 

RabbitMQ 是一款广泛使用的开源消息代理软件,它基于 AMQP 协议,提供了可靠、灵活的消息传递服务。在 .NET 应用程序中,我们可以利用 RabbitMQ 来实现异步通信、解耦服务、平衡负载等功能。本文将详细介绍如何在 .NET 中使用 RabbitMQ 的队列、死信队列、延时队列,以及一些实际应用场景。

RabbitMQ 队列基础 

安装 RabbitMQ.Client

在 .NET 项目中使用 RabbitMQ,首先需要安装 RabbitMQ.Client 库。可以通过 NuGet 包管理器来安装:

  • 使用包管理器控制台:
Install-Package RabbitMQ.Client
  • 使用 .NET CLI:
dotnet add package RabbitMQ.Client

创建生产者和消费者

生产者

生产者负责发送消息到 RabbitMQ 服务器。以下是一个简单的生产者示例:

using RabbitMQ.Client;
using System.Text;

class Producer
{
    public static void SendMessage(string message)
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            channel.QueueDeclare(queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null);

            var body = Encoding.UTF8.GetBytes(message);
            channel.BasicPublish(exchange: "", routingKey: "hello", basicProperties: null, body: body);
            Console.WriteLine(" [x] Sent {0}", message);
        }
    }
}

消费者

消费者负责从 RabbitMQ 服务器接收消息。以下是一个简单的消费者示例:

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

class Consumer
{
    public static void ReceiveMessage()
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            channel.QueueDeclare(queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null);

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body.ToArray();
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine(" [x] Received {0}", message);
            };
            channel.BasicConsume(queue: "hello", autoAck: true, consumer: consumer);

            Console.WriteLine(" Press [enter] to exit.");
            Console.ReadLine();
        }
    }
}

死信队列 

死信队列(Dead Letter Queue,简称 DLQ)用于存储和处理那些因为某些原因无法被正常消费的消息。以下是几种常见的死信队列形成场景:

  • 消息 TTL(Time To Live)过期
  • 队列达到最大长度
  • 消息被拒绝(basic.reject 或 basic.nack)并且 requeue=false

实现死信队列

以下是一个使用死信队列的示例:

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

class DeadLetterQueueExample
{
    public static void Setup()
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            // 声明死信交换机和死信队列
            channel.ExchangeDeclare("dead_letter_exchange", ExchangeType.Direct);
            channel.QueueDeclare("dead_letter_queue", durable: false, exclusive: false, autoDelete: false, arguments: null);
            channel.QueueBind("dead_letter_queue", "dead_letter_exchange", "dead_letter_routing_key");

            // 声明普通队列,并设置死信交换机和死信路由键
            var args = new Dictionary<string, object>
            {
                { "x-dead-letter-exchange", "dead_letter_exchange" },
                { "x-dead-letter-routing-key", "dead_letter_routing_key" }
            };
            channel.QueueDeclare("normal_queue", durable: false, exclusive: false, autoDelete: false, arguments: args);

            // 发送消息到普通队列
            var body = Encoding.UTF8.GetBytes("This message will be dead lettered.");
            channel.BasicPublish("", "normal_queue", null, body);
        }
    }

    public static void ConsumeDeadLetter()
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body.ToArray();
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine($"Received dead letter message: {message}");
            };
            channel.BasicConsume("dead_letter_queue", autoAck: true, consumer: consumer);

            Console.WriteLine(" Press [enter] to exit.");
            Console.ReadLine();
        }
    }
}

延时队列 

RabbitMQ 本身没有直接支持延时队列的功能,但可以通过 TTL(Time To Live)+ 死信队列的组合来实现。以下是实现延时队列的步骤:

  1. 创建一个普通队列,并设置其死信交换机和死信路由键。
  2. 将需要延迟处理的消息发送到这个队列,并设置消息的过期时间(TTL)。
  3. 当消息过期后,RabbitMQ 会将其发送到死信队列,而死信队列可以由消费者按照正常的方式进行处理。

实现延时队列

以下是一个使用延时队列的示例:

using RabbitMQ.Client;
using System.Text;

class DelayQueueExample
{
    public static void SendMessage(string message, int delayMilliseconds)
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            // 声明死信交换机和死信队列
            channel.ExchangeDeclare("delay_exchange", ExchangeType.Direct);
            channel.QueueDeclare("delay_queue", durable: false, exclusive: false, autoDelete: false, arguments: null);
            channel.QueueBind("delay_queue", "delay_exchange", "delay_routing_key");

            // 声明延时队列,并设置死信交换机和死信路由键
            var args = new Dictionary<string, object>
            {
                { "x-dead-letter-exchange", "delay_exchange" },
                { "x-dead-letter-routing-key", "delay_routing_key" }
            };
            channel.QueueDeclare("normal_queue", durable: false, exclusive: false, autoDelete: false, arguments: args);

            // 发送消息到普通队列,并设置 TTL
            var properties = channel.CreateBasicProperties();
            properties.Expiration = delayMilliseconds.ToString();
            var body = Encoding.UTF8.GetBytes(message);
            channel.BasicPublish("", "normal_queue", properties, body);
        }
    }
}

小应用示例 

订单超时自动取消

假设我们有一个在线商城,用户下单后需要在指定时间内完成支付,否则订单将自动取消。我们可以使用延时队列来实现这一功能:

  1. 用户下单时,将订单信息发送到延时队列,并设置 TTL 为指定的超时时间。
  2. 如果用户在超时时间内完成支付,可以从延时队列中移除该订单的消息。
  3. 如果用户未在超时时间内完成支付,订单消息将被发送到死信队列。
  4. 一个专门的消费者监听死信队列,当收到订单消息时,自动取消该订单,并进行相应的后续处理。

日志记录

在分布式系统中,日志记录是一个重要的功能。我们可以使用 RabbitMQ 的队列来实现日志的异步记录:

  1. 各个服务在生成日志时,将日志信息发送到一个日志队列。
  2. 一个专门的日志服务监听日志队列,当收到日志消息时,将其存储到日志数据库或文件系统中。

任务调度

RabbitMQ 可以用于实现任务调度系统:

  1. 将需要执行的任务发送到任务队列,每个任务可以包含任务的详细信息和执行时间。
  2. 任务消费者从任务队列中获取任务,并根据任务的执行时间将其放入延时队列。
  3. 当任务的执行时间到达时,任务消息从延时队列中释放,并被任务消费者获取。
  4. 任务消费者执行任务,并将任务的执行结果发送到结果队列。

结论 

RabbitMQ 提供了强大的消息队列功能,在 .NET 应用程序中,我们可以利用其队列、死信队列、延时队列等特性,实现异步通信、任务调度、日志记录。

责任编辑:武晓燕 来源: 程序员编程日记
相关推荐

2023-11-03 10:33:26

2024-04-15 00:00:00

RabbitMQ死信队列消息

2023-10-10 13:39:53

Spring队列优化

2023-04-27 07:43:22

RabbitMQ重试队列死信队列

2024-03-18 00:00:03

RabbitMQ代码延迟队列

2017-10-11 15:08:28

消息队列常见

2020-07-30 08:03:36

MQ死信队列

2023-08-08 08:28:03

消息消费端Spring

2023-10-23 10:02:58

RabbitMQ延迟队列

2023-09-05 15:48:14

RabbitMQ延迟队列

2024-05-10 11:35:22

Redis延时队列数据库

2021-10-15 10:39:43

RabbitMQ队列延迟

2024-05-16 08:10:17

RabbitMQ软件通信机制

2024-04-19 00:47:07

RabbitMQ消息机制

2022-09-21 12:01:22

消息队列任务队列任务调度

2021-03-01 23:31:48

队列实现栈存储

2010-04-21 12:12:56

Unix 消息队列

2019-11-17 22:11:11

TCPSYN队列Accept队列

2021-10-20 07:18:51

Linux延时队列

2024-01-26 13:16:00

RabbitMQ延迟队列docker
点赞
收藏

51CTO技术栈公众号