RabbitMQ 延迟消息实现:两种方案全解析(TTL+死信 / 延迟插件)实战教程
- 前言
- 一、延迟消息基础认知:延迟消息是什么?
- 1.1 定义
- 1.2 典型业务场景
- 1.3 延迟消息流程图(通用)
- 二、RabbitMQ 实现延迟消息的两种方案
- 方案一:TTL + 死信队列(DLX)【原生方案,无需插件】
- 方案二:RabbitMQ Delayed Message Plugin【官方插件,更强大】
- 三、方案一:TTL + 死信队列 实现延迟消息(原生)
- 3.1 实现原理(最经典)
- 3.2 完整流程图
- 3.3 SpringBoot 实战代码
- 1. 配置类(核心)
- 2. 消费者(监听死信队列)
- 3. 生产者发送消息
- 3.4 优点与缺点
- 四、方案二:延迟插件实现(官方推荐,最灵活)
- 4.1 实现原理
- 4.2 插件版流程图
- 4.3 插件安装步骤
- 4.4 SpringBoot 插件版实战代码
- 1. 配置类
- 2. 生产者(动态设置延迟时间)
- 3. 消费者
- 4.5 优点与缺点
- 五、两种延迟方案对比(面试/生产必看)
- 六、生产环境最佳实践
- 七、总结
- 延迟消息实现核心总结
- 文末说明
🌺The Begin🌺点点关注,收藏不迷路🌺 |
前言
在实际业务开发中,延迟消息是非常高频的需求:订单超时未支付自动取消、用户注册30分钟未完善资料提醒、外卖超时自动退款、预约任务定时执行等。
RabbitMQ本身不直接提供延迟队列,但可以通过两种成熟方案实现延迟消息,本文会详细讲解原理、流程图、代码实战、优缺点对比,让你在生产环境中快速落地。
一、延迟消息基础认知:延迟消息是什么?
1.1 定义
延迟消息:消息发送后,不立即被消费,等待指定延迟时间(如15分钟)后,才会被消费者接收并处理。
1.2 典型业务场景
- 订单15分钟未支付 → 自动取消
- 红包24小时未领取 → 自动退回
- 预约服务到期提醒
- 超时未评价自动好评
- 外卖超时自动取消
1.3 延迟消息流程图(通用)
二、RabbitMQ 实现延迟消息的两种方案
RabbitMQ 实现延迟消息有两种标准方案:
方案一:TTL + 死信队列(DLX)【原生方案,无需插件】
方案二:RabbitMQ Delayed Message Plugin【官方插件,更强大】
下面分别详细讲解。
三、方案一:TTL + 死信队列 实现延迟消息(原生)
3.1 实现原理(最经典)
- 给队列/消息设置TTL 过期时间(=延迟时间)
- 消息过期后变成死信
- 死信被转发到死信队列
- 消费者监听死信队列→ 实现延迟执行
3.2 完整流程图
3.3 SpringBoot 实战代码
1. 配置类(核心)
@ConfigurationpublicclassTtlDlxConfig{// 正常交换机 + 队列publicstaticfinalStringNORMAL_EX="normal.exchange";publicstaticfinalStringNORMAL_QUEUE="normal.queue";publicstaticfinalStringNORMAL_RK="normal.rk";// 死信交换机 + 队列publicstaticfinalStringDLX_EX="dlx.exchange";publicstaticfinalStringDLX_QUEUE="dlx.queue";publicstaticfinalStringDLX_RK="dlx.rk";// ==================== 正常队列(设置TTL+死信)====================@BeanpublicQueuenormalQueue(){Map<String,Object>args=newHashMap<>();args.put("x-message-ttl",10000);// 延迟10秒args.put("x-dead-letter-exchange",DLX_EX);args.put("x-dead-letter-routing-key",DLX_RK);returnnewQueue(NORMAL_QUEUE,true,false,false,args);}@BeanpublicDirectExchangenormalExchange(){returnnewDirectExchange(NORMAL_EX);}@BeanpublicBindingnormalBinding(){returnBindingBuilder.bind(normalQueue()).to(normalExchange()).with(NORMAL_RK);}// ==================== 死信队列 ====================@BeanpublicQueuedlxQueue(){returnnewQueue(DLX_QUEUE);}@BeanpublicDirectExchangedlxExchange(){returnnewDirectExchange(DLX_EX);}@BeanpublicBindingdlxBinding(){returnBindingBuilder.bind(dlxQueue()).to(dlxExchange()).with(DLX_RK);}}2. 消费者(监听死信队列)
@ComponentpublicclassDelayConsumer{// 监听死信队列@RabbitListener(queues=TtlDlxConfig.DLX_QUEUE)publicvoidreceive(Stringmsg){System.out.println("延迟消息已消费:"+msg);// 执行:取消订单、超时任务...}}3. 生产者发送消息
@ServicepublicclassDelayProducer{@AutowiredprivateRabbitTemplaterabbitTemplate;publicvoidsend(Stringmsg){rabbitTemplate.convertAndSend(TtlDlxConfig.NORMAL_EX,TtlDlxConfig.NORMAL_RK,msg);System.out.println("延迟消息已发送");}}3.4 优点与缺点
✅优点:
- 无需安装插件
- 原生支持,稳定可靠
- 适合固定延迟时间业务
❌缺点:
- 每一种延迟时间都要创建一个队列(10s、30s、60s…)
- 消息 TTL 存在懒检查问题,会导致延迟不准
- 灵活性差
四、方案二:延迟插件实现(官方推荐,最灵活)
4.1 实现原理
- 安装 RabbitMQ 官方延迟消息插件:
rabbitmq_delayed_message_exchange - 创建x-delayed-message 类型交换机
- 发送消息时指定
x-delay延迟时间 - 插件内部延迟调度,时间到后再路由到队列
4.2 插件版流程图
4.3 插件安装步骤
- 下载对应版本插件:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases
- 放到 RabbitMQ 插件目录
plugins - 启用插件:
rabbitmq-pluginsenablerabbitmq_delayed_message_exchange- 重启 RabbitMQ
4.4 SpringBoot 插件版实战代码
1. 配置类
@ConfigurationpublicclassPluginDelayConfig{publicstaticfinalStringDELAY_EX="plugin.delay.exchange";publicstaticfinalStringDELAY_QUEUE="plugin.delay.queue";publicstaticfinalStringDELAY_RK="plugin.delay.rk";// 声明延迟交换机(关键:x-delayed-message)@BeanpublicCustomExchangedelayExchange(){Map<String,Object>args=newHashMap<>();args.put("x-delayed-type","direct");returnnewCustomExchange(DELAY_EX,"x-delayed-message",true,false,args);}@BeanpublicQueuedelayQueue(){returnnewQueue(DELAY_QUEUE);}@BeanpublicBindingdelayBinding(){returnBindingBuilder.bind(delayQueue()).to(delayExchange()).with(DELAY_RK).noargs();}}2. 生产者(动态设置延迟时间)
@ServicepublicclassPluginProducer{@AutowiredprivateRabbitTemplaterabbitTemplate;publicvoidsend(Stringmsg,IntegerdelayTime){rabbitTemplate.convertAndSend(PluginDelayConfig.DELAY_EX,PluginDelayConfig.DELAY_RK,msg,message->{// 设置延迟时间(毫秒)message.getMessageProperties().setDelay(delayTime);returnmessage;});}}3. 消费者
@ComponentpublicclassPluginConsumer{@RabbitListener(queues=PluginDelayConfig.DELAY_QUEUE)publicvoidreceive(Stringmsg){System.out.println("插件版延迟消息消费:"+msg);}}4.5 优点与缺点
✅优点:
- 一个交换机支持任意延迟时间
- 动态设置延迟,无需创建多个队列
- 延迟精准,无懒检查问题
- 生产环境首选方案
❌缺点:
- 需要安装插件
- 旧版 RabbitMQ 不支持
五、两种延迟方案对比(面试/生产必看)
| 方案 | 实现方式 | 灵活性 | 延迟精度 | 生产推荐 |
|---|---|---|---|---|
| TTL+死信 | 原生 | 低(固定时间) | 一般(有懒检查) | 简单固定场景 |
| 延迟插件 | 官方插件 | 极高(动态时间) | 精准 | ⭐⭐⭐⭐⭐ 强烈推荐 |
六、生产环境最佳实践
- 动态延迟任务优先使用插件版
- 固定延迟(如15分钟订单)可使用 TTL+死信
- 延迟消息必须持久化,避免宕机丢失
- 消费者必须手动ACK,保证消息可靠消费
- 延迟时间单位:毫秒(ms)
七、总结
延迟消息实现核心总结
- RabbitMQ无原生延迟队列,必须通过方案实现
- 方案一:TTL + 死信队列 → 固定延迟、无需插件
- 方案二:延迟消息插件 →动态延迟、精准、推荐使用
- 核心用途:订单超时取消、任务定时执行
- 生产环境优先选择:延迟插件方案
掌握延迟消息,你就能解决 RabbitMQ 中90%的超时/定时业务场景!
文末说明
本文属于 RabbitMQ 高级实战核心篇,后续将更新消息幂等性、高可用集群、流量削峰、消息堆积排查等内容,欢迎点赞、收藏、关注!
🌺The End🌺点点关注,收藏不迷路🌺 |