RabbitMQ实战:延迟队列实现全解析——原理+2种方案+代码+生产避坑

张开发
2026/4/17 22:48:25 15 分钟阅读

分享文章

RabbitMQ实战:延迟队列实现全解析——原理+2种方案+代码+生产避坑
RabbitMQ实战延迟队列实现全解析——原理2种方案代码生产避坑一、前言二、基础认知什么是延迟队列2.1 延迟队列定义2.2 延迟队列核心应用场景2.3 延迟队列实现流程图三、RabbitMQ 实现延迟队列的 2 种方案四、方案1死信队列 TTL 实现延迟原生方案4.1 核心原理4.2 核心组件4.3 架构流程图4.4 SpringBoot 代码实现1. 配置类交换机 队列 绑定2. 生产者3. 消费者监听死信队列4.5 优点4.6 缺点五、方案2延迟交换机插件实现生产推荐5.1 核心原理5.2 优势5.3 架构流程图5.4 插件安装步骤5.5 SpringBoot 代码实现1. 配置类2. 生产者动态设置延迟时间3. 消费者5.6 优点5.7 缺点六、2 种延迟方案深度对比七、生产环境延迟队列最佳实践八、总结一句话结论The Begin点点关注收藏不迷路一、前言在实际业务场景中延迟任务无处不在订单超时未支付自动取消发货后未收货自动确认预约通知、定时提醒验证码超时失效这些场景都需要消息在指定延迟时间后才被消费而 RabbitMQ原生并不直接支持延迟队列但我们可以通过死信队列 TTL或官方延迟插件完美实现。本文将详细讲解RabbitMQ 延迟队列的 2 种实现方案从原理、流程图、代码实战、优缺点、生产选型全方位覆盖直接可用于生产环境。二、基础认知什么是延迟队列2.1 延迟队列定义延迟队列 消息进入队列后等待指定延迟时间才会被消费者消费消息发送后不会立即被消费等待 N 秒/分钟/小时后自动触发消费本质定时任务 消息队列2.2 延迟队列核心应用场景订单超时未支付自动关闭未签收订单自动确认收货定时通知、短信提醒验证码超时失效延迟重试机制2.3 延迟队列实现流程图生产者发送延迟消息设置消息过期时间TTL消息进入等待队列等待TTL超时消息变为死信转发至死信队列消费者监听死信队列开始消费三、RabbitMQ 实现延迟队列的 2 种方案RabbitMQ 官方提供2 种标准延迟队列方案方案1死信队列 TTL原生方案无需插件方案2延迟交换机插件官方插件推荐生产四、方案1死信队列 TTL 实现延迟原生方案4.1 核心原理创建普通队列TT队列不设置消费者给队列/消息设置TTL 过期时间消息过期后变成死信Dead Letter死信自动转发到配置好的死信交换机DLX消费者监听死信队列实现延迟消费4.2 核心组件业务交换机Biz ExchangeTT 等待队列无消费者死信交换机DLX Exchange死信队列真正消费队列4.3 架构流程图生产者业务交换机TT等待队列设置TTL消息过期转发至死信交换机DLX死信队列消费者监听消费4.4 SpringBoot 代码实现1. 配置类交换机 队列 绑定ConfigurationpublicclassTtlDelayConfig{// 1. 死信交换机publicstaticfinalStringDLX_EXCHANGEdlx.exchange;// 2. 死信队列publicstaticfinalStringDLX_QUEUEdlx.queue;// 3. TT等待队列过期队列publicstaticfinalStringTT_QUEUEtt.queue;// 4. 业务交换机publicstaticfinalStringBUSINESS_EXCHANGEbusiness.exchange;// 死信交换机BeanpublicDirectExchangedlxExchange(){returnnewDirectExchange(DLX_EXCHANGE);}// 死信队列BeanpublicQueuedlxQueue(){returnnewQueue(DLX_QUEUE);}// TT等待队列配置死信转发 TTLBeanpublicQueuettQueue(){MapString,ObjectargsnewHashMap();// 死信交换机args.put(x-dead-letter-exchange,DLX_EXCHANGE);// 死信路由键args.put(x-dead-letter-routing-key,dlx.routing.key);// 设置延迟时间10秒10000msargs.put(x-message-ttl,10000);returnnewQueue(TT_QUEUE,true,false,false,args);}// 业务交换机BeanpublicDirectExchangebusinessExchange(){returnnewDirectExchange(BUSINESS_EXCHANGE);}// 绑定TT队列BeanpublicBindingttBinding(){returnBindingBuilder.bind(ttQueue()).to(businessExchange()).with(tt.routing.key);}// 绑定死信队列BeanpublicBindingdlxBinding(){returnBindingBuilder.bind(dlxQueue()).to(dlxExchange()).with(dlx.routing.key);}}2. 生产者ComponentpublicclassDelayProducer{AutowiredprivateRabbitTemplaterabbitTemplate;publicvoidsendDelayMsg(Stringmsg){// 发送到业务交换机 → TT队列rabbitTemplate.convertAndSend(TtlDelayConfig.BUSINESS_EXCHANGE,tt.routing.key,msg);System.out.println(发送延迟消息10秒后消费msg);}}3. 消费者监听死信队列ComponentpublicclassDelayConsumer{// 监听死信队列RabbitListener(queuesTtlDelayConfig.DLX_QUEUE)publicvoidconsume(Stringmsg){System.out.println(延迟消费成功消息msg时间newDate());}}4.5 优点无需插件原生支持兼容性强所有版本都能用实现简单4.6 缺点只能固定延迟时间多个延迟等级需要创建多个队列存在队列头阻塞问题前面消息未过期后面消息无法过期五、方案2延迟交换机插件实现生产推荐5.1 核心原理安装 RabbitMQ 官方延迟消息插件rabbitmq_delayed_message_exchange创建延迟交换机x-delayed-message消息发送时携带延迟时间插件内部延迟消息到期后路由到队列消费者直接监听业务队列5.2 优势支持动态延迟时间每条消息可不同一个队列支持所有延迟级别无队列头阻塞问题生产环境标准方案5.3 架构流程图生产者发送消息设置延迟时间延迟交换机插件插件内部暂存消息计时等待时间到达路由到业务队列消费者正常消费5.4 插件安装步骤下载对应版本插件https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases上传到插件目录cp插件.ez /usr/lib/rabbitmq/plugins/启用插件rabbitmq-pluginsenablerabbitmq_delayed_message_exchange5.5 SpringBoot 代码实现1. 配置类ConfigurationpublicclassPluginDelayConfig{publicstaticfinalStringDELAY_EXCHANGEplugin.delay.exchange;publicstaticfinalStringDELAY_QUEUEplugin.delay.queue;publicstaticfinalStringROUTING_KEYplugin.routing.key;// 延迟交换机CustomExchangeBeanpublicCustomExchangedelayExchange(){MapString,ObjectargsnewHashMap();// 交换机类型direct/topic/fanoutargs.put(x-delayed-type,direct);returnnewCustomExchange(DELAY_EXCHANGE,x-delayed-message,true,false,args);}// 业务队列BeanpublicQueuedelayQueue(){returnnewQueue(DELAY_QUEUE);}// 绑定BeanpublicBindingbinding(){returnBindingBuilder.bind(delayQueue()).to(delayExchange()).with(ROUTING_KEY).noargs();}}2. 生产者动态设置延迟时间ComponentpublicclassPluginDelayProducer{AutowiredprivateRabbitTemplaterabbitTemplate;/** * 发送延迟消息 * param msg 消息内容 * param delayTime 延迟时间毫秒 */publicvoidsend(Stringmsg,intdelayTime){rabbitTemplate.convertAndSend(PluginDelayConfig.DELAY_EXCHANGE,PluginDelayConfig.ROUTING_KEY,msg,message-{// 设置延迟时间message.getMessageProperties().setDelay(delayTime);returnmessage;});System.out.println(发送延迟消息msg延迟delayTime/1000秒);}}3. 消费者ComponentpublicclassPluginDelayConsumer{RabbitListener(queuesPluginDelayConfig.DELAY_QUEUE)publicvoidconsume(Stringmsg){System.out.println(插件延迟消费成功msg时间newDate());}}5.6 优点动态延迟每条消息可自定义时间一个队列支持所有延迟级别无队列头阻塞性能高、稳定可靠官方推荐生产使用5.7 缺点需要安装插件不支持 Quorum 仲裁队列3.93.12 需注意六、2 种延迟方案深度对比对比维度死信队列 TTL延迟交换机插件实现方式原生RabbitMQ官方插件延迟时间固定队列级别动态消息级别队列数量多延迟多队列一个队列通用队列头阻塞存在不存在灵活性低极高生产推荐一般强烈推荐复杂度低中七、生产环境延迟队列最佳实践优先使用插件方案灵活、高效、无阻塞订单、支付等核心场景必须开启持久化消费者使用手动ACK确保消息不丢失结合死信队列做异常兜底高可用集群使用镜像队列插件暂不支持Quorum八、总结RabbitMQ 原生不支持延迟队列必须通过方案实现方案1死信TTL无需插件、固定延迟、简单但有缺陷方案2延迟插件动态延迟、灵活高效、生产首选核心业务订单超时强烈推荐插件方案简单固定延迟场景可使用死信方案一句话结论生产环境实现延迟队列优先选择官方延迟插件方案稳定、灵活、无坑The End点点关注收藏不迷路

更多文章