rabbitmq 延迟队列的使用

本文介绍了如何在RabbitMQ中使用死信队列和rabbitmq-delayed-message-exchange插件实现延迟队列功能,包括配置步骤、消息进入死信队列的条件以及插件安装和使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在工作中总有那么一下场景需要使用到延迟队列

举个常见的例子:订单x分钟后如果未付款自动取消、更改某项配置并且设定1天后才生效
针对上述场景我们都可以使用延迟队列来解决

实现延迟队列有如下2种方式

  • 死信(Dead Lettering)队列
  • 插件(rabbitmq-delayed-message-exchange)

死信(Dead Lettering)队列

有以下几种操作会导致消息进入死信(Dead Lettering)队列

  • 消费者使用basic.nack或者basic.reject并且将requeue参数设置为false否定消息时
  • 设置了消息的TTL并且过期时
  • 队列长度超过限制时消息被丢弃

如果没有配置死信那么消息将会被丢弃

如何配置

先瞜一眼官方的说明
image.png

将“dead-letter-exchange” 添加到策略定义中

spring boot中我们该如何呢
我们可以看到Queue参数最多的构造方法,最后有一个arguments字段
image.png
我们在这个字段传入“dead-letter-exchange”

// 死信队列的binding
// Binding binding
Map<String, Object> arguments = new HashMap<>(16);
arguments.put("x-dead-letter-exchange", binding.getExchange());
arguments.put("x-dead-letter-routing-key", binding.getRoutingKey());
// 可以设置TTL
// arguments.put("x-message-ttl", 10000);
// QueueBuilder.ttl(10000)也行
// Queue queue = new Queue("xxx", true, false, false, arguments);
Queue queue = QueueBuilder.durable(DEMO_QUEUE).withArguments(arguments).build();

死信队列声明和普通的队列没有区别

@Bean
public DirectExchange dlxDirectExchange() {
    return new DirectExchange(DLX_DIRECT_EXCHANGE);
}

@Bean
public Queue dlxQueue() {
    return new Queue(DLX_QUEUE);
}

@Bean
public Binding dlxHandlerBinding(@Qualifier("dlxQueue") Queue queue,
                                     @Qualifier("dlxDirectExchange") DirectExchange exchange) {
    return BindingBuilder.bind(queue).to(exchange).with(DLX_HANDLER_ROUTING_KEY);
}

发消息

紧接着在发送消息的时候指定TTL或者上面剩余两种操作都可以

// 单位是ms。假设是1秒,expiration="1000"
String finalExpiration = expiration;
// binding是上面绑定"x-dead-letter-exchange"队列所对应的binding
rabbitTemplate.convertAndSend(binding.getExchange(),
        binding.getRoutingKey(),
        dataMessage,
        message -> {
            MessageProperties messageProperties = message.getMessageProperties();
            // 设置消息过期时间
            messageProperties.setExpiration(finalExpiration);
            return message;
        });

注:消息和队列的过期时间那个小取那个

如果我们先放一条10s过期的消息A,再放入一条5s过期的消息B
消息B会先进入死信队列吗?
答案是否定的,队列会遵循先入先出的规则。B在消息A过期后随着A一起进入死信队列被消费者消费
看起来并不是完美的延迟队列,下面我们看插件方式

延迟队列插件

在3.5.8以后官方推荐使用rabbitmq-delayed-message-exchange插件来解决延迟队列
官网插件地址:Community Plugins — RabbitMQ
image.png
GitHub:Releases · rabbitmq/rabbitmq-delayed-message-exchange

⚠️需要注意,插件对版本是有要求的
image.png

插件安装

将插件下载到rabbitmq的插件目录
然后执行如下命令即可
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
我们重新打开RabbitMQ Management可以看到exchange中有x-delayed-message类型,说明插件安装成功了
image.png

延迟队列的使用

只有交换机的定义有所区别,其余的没有区别

HashMap<String, Object> arguments = new HashMap<>(2);
// 需要指定delayed-type,可以是:direct、fanout、topic、headers
arguments.put("x-delayed-type", "direct");
// 参数依次含义是:交换机名称、交换机类型、持久化、自动删除、自定义交换机参数
CustomExchange exchange = new CustomExchange("exchange-name", "x-delayed-message", true, false, arguments);

我们需要手动指定交换机类型为x-delayed-message并且需要一个参数x-delayed-type,参数值上面有写

// binding是绑定"x-delayed-message"类型的交换机对应的binding
rabbitTemplate.convertAndSend(binding.getExchange(),
        binding.getRoutingKey(),
        dataMessage,
        message -> {
            MessageProperties messageProperties = message.getMessageProperties();
            // 设置延时时间。单位:ms
            messageProperties.setDelay(1000);
            return message;
        });
### RabbitMQ 延迟队列插件使用指南 #### 插件简介 RabbitMQ 提供了一种通过插件实现延迟队列的功能。此功能允许消息在被消费者处理之前等待指定的时间间隔。为了启用这一特性,需安装并配置 `rabbitmq_delayed_message_exchange` 插件。 --- #### 安装与启动插件 要使用延迟队列插件,首先需要将其下载到 RabbitMQ 的插件目录下,并完成必要的初始化操作: 1. **下载插件** 下载适用于当前版本的 `rabbitmq_delayed_message_exchange` 插件文件(通常为 `.ez` 文件),并将它放置于 RabbitMQ 安装路径下的 `/plugins` 目录中[^2]。 2. **启用插件** 执行以下命令以激活插件: ```bash rabbitmq-plugins enable rabbitmq_delayed_message_exchange ``` 3. **验证插件状态** 可运行如下命令确认插件已成功加载: ```bash rabbitmq-plugins list ``` 如果插件正常工作,在列表中应能看到其名称标记为 `[E]` 表示已启用。 4. **重启服务** 修改完成后建议重新启动 RabbitMQ 服务以应用更改: ```bash systemctl restart rabbitmq-server ``` --- #### 配置延迟队列 一旦插件就绪,可以通过创建特定类型的 Exchange 来定义延迟行为。以下是具体步骤: 1. **声明 Delayed Message Exchange** 创建一个类型为 `x-delayed-message` 的 Exchange 实例。例如,利用 AMQP 协议客户端执行以下代码片段: ```python import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() arguments = {'x-delayed-type': 'direct'} channel.exchange_declare(exchange='delayed_exchange', exchange_type='x-delayed-message', arguments=arguments) connection.close() ``` 2. **发送带延迟的消息** 发送消息时附加头字段 `x-delay`,单位为毫秒。下面是一个 Python 示例展示如何向上述 Exchange 推送一条具有固定延迟时间的数据包: ```python properties = pika.BasicProperties(headers={'x-delay': 5000}) # 设置延迟时间为5秒钟 channel.basic_publish( exchange='delayed_exchange', routing_key='test_queue', body='Delayed message example.', properties=properties ) ``` 3. **消费端逻辑** 消费者无需特别调整即可接收到经过设定延时期待后的消息。对于死信队列场景中的监听器设计可参见实例代码[^4]: ```java @RabbitListener(queues = "dl.queue") public void listenDlQueue(String msg) { log.info("消费者接收到了 dl.queue 的延迟消息:{}", msg); } ``` --- #### 注意事项 尽管 RabbitMQ 支持最长至约 49 天的最大 TTL 时间窗口[^1],但在实际生产环境中推荐依据业务需求合理规划超时范围以免资源浪费或者性能瓶颈问题发生。当遇到超出预期时限的任务调度请求时,可能需要探索替代方案比如 Redis 或专门化的作业管理系统来弥补不足之处。 --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值