RabbitMQ使用TTL+死信队列实现延迟消息队列 纯注解式

1. 引言

本文将介绍如何使用 RabbitMQ 注解,通过设置 TTL 和死信队列,实现纯注解方式的延迟消息队列。另外:我们可以使用 RabbitMQ 官方的延迟队列插件来实现延迟队列,这里不说明,感兴趣可以自己去学习。

  • TTL + 死信队列 方式:

    • 适用于更灵活的场景,允许在代码层面直接控制延迟队列的配置。
    • 适用于小型项目或者特定队列需要个性化配置的情况
  • 插件方式:

    • 适用于需要全局配置延迟队列机制的情况。
    • 适用于不希望将延迟队列的配置与代码混合的情况。

2. TTL 的概述

消息的 Time-To-Live(TTL)是消息在队列中存活的时间。在 RabbitMQ 中,我们可以使用 TTL 控制消息的生命周期,从而实现延迟消息的效果。

3. 死信队列的介绍

死信队列用于处理过期或被拒绝的消息。通过设置死信队列,我们可以有效地处理延迟消息队列中的失效消息,确保系统的可靠性。

4. 为什么需要延迟消息队列

延迟消息队列在任务调度、定时任务等场景中具有广泛应用。它使得我们能够以更灵活的方式处理需要延迟执行的业务逻辑。下面简单说个例子。

订单超时处理:

  • 场景描述: 在电子商务中,当用户下单后,有时需要等待用户支付。如果用户在规定的时间内没有完成支付,可能需要取消订单。
  • 延迟消息应用: 将订单信息发送到延迟消息队列,并设置合适的延迟时间。如果在规定时间内用户未支付,延迟队列会触发订单超时的处理逻辑

5. RabbitMQ 注解的介绍

RabbitMQ 注解是一种简化 RabbitMQ 操作的方式,通过注解可以更轻松地配置队列、交换机和消息监听器。常见的注解包括 @Queue@Exchange@RabbitListener 等。

6. 纯注解实现延迟消息队列

在这一部分,我将演示如何使用 RabbitMQ 注解实现延迟消息队列。我们将配置队列的 TTL 和死信队列,以确保消息在一定时间后被正确处理。

7. 示例代码

以下是一个简化的示例代码,展示了如何使用 RabbitMQ 注解实现延迟消息队列。

特别说明:下面的示例代码中,消费者的参数 Message,使用的是下面的Message包。

arduino 复制代码
import org.springframework.messaging.Message;

定义正常的业务交换机和队列,但不开启此消费者(不开启消费者,队列中的消息无法处理,等过了TTL,消息就会被发送到死信队列)

  • 设置死信交换机和死信key,指定队列的消息 TTL

注意 :在@RabbitListener注解中,可以使用autoStartup属性来控制消费者的启动和关闭。默认情况下,autoStartup属性的值为true,表示消费者将会自动启动。我们可以将其设置为false,以关闭消费者进行测试。

less 复制代码
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "nomal_queue",
                    durable="true", // 持久化可设置为 true
                    arguments = {
                            @Argument(name = "x-dead-letter-exchange",value = "dead_letter_exchange"), // 死信交换机
                            @Argument(name = "x-dead-letter-routing-key",value = "dead_letter_key"), // 死信key
                            @Argument(name = "x-message-ttl",value = "10000", type = "java.lang.Integer"), // todo: TTL设置为 10000ms, 即 10秒。在这里是设置整个队列的消息TTL,也可以在生产者里定义单个消息的TTL
                    }),

            exchange = @Exchange(value = "nomal_exchange",
                    durable="true",
                    ignoreDeclarationExceptions = "true"),
            key = {"nomal_key"}
    ),
        autoStartup = "false" // 设置为false以关闭消费者,下面的消费代码不会执行
    )
    @RabbitHandler
    public void onNomalHandler(Message message, Channel channel) throws Exception {
        // 打印日志
        log.info("onNomalHandler 消息id为={}, 接收到的Payload={}",messageId, message.getPayload());

        // 模拟执行过程出异常,将消息放回队列
        Thread.sleep(1000);
        channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
        // 手工ACK
//        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        // 拒绝消息
//        channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
}

定义死信交换机和队列

less 复制代码
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "dead_letter_queue",
                    durable="true"),
            exchange = @Exchange(value = "dead_letter_exchange",
                    durable="true",
                    ignoreDeclarationExceptions = "true"),
            key = {"dead_letter_key"}
    ))
    @RabbitHandler
    public void onDelayHandler(Message message, Channel channel) throws Exception {
        String messageId = message.getHeaders().getId().toString();
        // 打印日志,调式
        log.info("onDelayHandler 死信队列 消息id为={}, 接收到的Payload={}", messageId, message.getPayload());

        // 手工ACK
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

    }

定义生产者,示例通过编写测试单元

typescript 复制代码
    @Test
    void testDelayQueue(){
        String msg = "this is a test message";
        rabbitTemplate.convertAndSend("nomal_exchange", "nomal_key", msg);
    }

8. 总结

通过本文,我们了解了如何使用 RabbitMQ 注解、TTL 和死信队列实现延迟消息队列。这种纯注解的方式使得配置更加简便,提高了代码的可读性和可维护性。希望读者能够通过这些知识,更好地利用 RabbitMQ 构建灵活而可靠的消息系统。

9. 参考资料

scss 复制代码
[https://www.rabbitmq.com/documentation.html](url)
[https://docs.spring.io/spring-amqp/docs/current/reference/html/](url)

相关推荐
小宋10212 小时前
玩转RabbitMQ声明队列交换机、消息转换器
服务器·分布式·rabbitmq
xcx00318 小时前
快充协议方案,Type-C接口受电端Sink取电快充协议芯片
zookeeper·rabbitmq·flume·memcached·storm
杰信步迈入C++之路19 小时前
【RabbitMQ】快速上手
分布式·rabbitmq·ruby
c1tenj219 小时前
docker创建rabbitmq容器
java·rabbitmq·java-rabbitmq
sdg_advance1 天前
RabbitMQ消费者确认和重复机制
rabbitmq·java-rabbitmq
小宋10211 天前
RabbitMQ:交换机详解(Fanout交换机、Direct交换机、Topic交换机)
服务器·网络·rabbitmq
谢尔登1 天前
【Node.js】RabbitMQ 不同交换器类型的使用
node.js·rabbitmq·ruby
ok你也是个coder2 天前
RabbitMQ 基础入门
rabbitmq·rabbitmq基础入门
会有黎明吗2 天前
完整版订单超时自动取消功能
java·vue·rabbitmq
圆头圆脑圆JAVA2 天前
MQ(RabbitMQ)笔记
笔记·rabbitmq·java-rabbitmq