尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
RabbitMQ死信交换机和延迟队列
死信交换机DLX‌和‌延迟队列‌是解决“异常兜底”与“定时调度”两大核心场景的关键机制。二者虽常配合使用但定位截然不同一、死信交换机DLX异常消息的“回收站”死信交换机本身不是特殊的交换机类型而是普通交换机被配置为‌接收“死信”消息的目标‌。‌触发条件消息变死信的三种情况‌‌消费者拒收‌调用 basic.nack/reject 且 requeuefalse。‌消息过期‌消息在队列中存活时间超过 TTL 且未被消费。‌队列满员‌队列达到最大长度限制新消息进入时挤出的旧消息。‌核心作用‌‌防止消息丢失‌当业务处理失败且不再重试时消息不会直接丢弃而是转入死信队列存储。‌故障排查与补偿‌开发人员可监控死信队列分析失败原因如数据格式错误、依赖服务宕机并进行人工补偿或编写专用程序重新处理。‌配置要点‌需在‌原业务队列‌声明时指定 x-dead-letter-exchange 参数指向一个普通的 Direct 或 Topic 交换机。二、延迟队列定时任务的“调度器”延迟队列用于实现‌消息在指定时间后才被消费者可见‌常用于订单超时取消、延时通知等场景。‌主流实现方案对比方案实现原理优点缺点‌插件方式推荐‌安装 rabbitmq-delayed-message-exchange 插件消息存储在 Mnesia 数据库中到期后投递。支持任意延迟时间无需创建大量队列无队头阻塞。需安装插件集群需同步插件状态。‌TTL DLX 方式‌利用消息 TTL 过期后自动转入死信队列的特性。设置一个临时队列 TTL30min绑定到 DLXDLX 再路由到真实业务队列。无需额外插件原生支持。只能实现固定时长延迟若需多种延迟时间需创建多个队列存在队头阻塞问题。‌核心优势‌‌解耦定时逻辑‌业务代码只需发送消息并指定延迟时间无需引入 Quartz 等重型定时任务框架。‌高可靠性‌基于 MQ 的持久化机制比内存定时任务更抗重启风险。三、二者协同工作场景在实际业务中DLX 和延迟队列常形成闭环‌场景‌订单支付超时自动取消。‌流程‌用户下单后发送一条延迟 30 分钟的消息到‌延迟交换机‌。30 分钟后消息投递到‌订单取消业务队列‌。消费者尝试取消订单若因数据库锁或网络故障导致处理失败且重试多次后仍失败。消费者拒绝消息nack消息转入‌死信交换机‌绑定的‌死信队列‌。监控系统发现死信队列有消息触发告警人工介入或启动补偿脚本。四、避坑指南‌插件优先‌除非环境限制否则强烈建议使用延迟插件避免 TTL 方案带来的队列爆炸和维护难题。‌死信监控‌死信队列不能只存不管必须配套监控告警否则会变成“数据黑洞”。‌幂等性‌无论是延迟消息的重投还是死信消息的补偿处理消费者端都必须严格执行‌幂等性校验‌防止数据重复处理。四、死信队列DLQ异常消息的“避难所”死信队列的核心目的是‌兜底‌。当消息无法正常被消费者处理时将其路由到另一个专门的队列中避免消息丢失方便后续人工排查或补偿处理。1. 消息变成“死信”的三种情况‌消费者主动拒绝‌调用 basic.nack 或 basic.reject 且设置 requeuefalse表示消息不再重新回到原队列。‌消息过期TTL‌消息在队列中存活时间超过了设定的 TTLTime-To-Live且未被消费。‌队列达到最大长度‌队列消息数超过 x-max-length限制新消息进入时最旧的消息会被挤出并标记为死信。2. 工作原理原队列必须配置‌死信交换机DLX, Dead Letter Exchange‌。当消息满足上述任一条件变成死信后RabbitMQ 会自动将该消息发布到绑定的 DLXDLX 再根据路由键Routing Key将消息转发到绑定的‌死信队列DLQ‌中存储。如果原队列未绑定 DLX死信消息会被直接丢弃。3. 配置要点‌持久化保障‌务必给 DLX、原队列以及死信队列都设置持久化属性防止 RabbitMQ 重启后配置或消息丢失。‌绑定关系‌DLX 与普通交换机的配置逻辑一致需要建立 DLX 与死信队列之间的 Binding。五、完整代码示例Spring Boot RabbitMQ 实现死信交换机和延迟队列下面通过一个完整的 Spring Boot 项目示例演示如何配置和使用死信交换机DLX以及延迟队列使用插件方式。1. 环境准备依赖配置pom.xmldependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-amqp/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencyapplication.yml 配置spring:rabbitmq:host:localhostport:5672username:guestpassword:guestvirtual-host:/# 开启消息确认用于死信场景publisher-confirms:truepublisher-returns:truelistener:simple:acknowledge-mode:manual# 手动ACK便于控制重试和死信2. 死信交换机DLX配置示例importorg.springframework.amqp.core.*;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationpublicclassDlqConfig{// 原业务交换机BeanpublicDirectExchangeorderExchange(){returnnewDirectExchange(order.exchange);}// 死信交换机BeanpublicDirectExchangeorderDlxExchange(){returnnewDirectExchange(order.dlx.exchange);}// 原业务队列 - 配置死信参数BeanpublicQueueorderQueue(){returnQueueBuilder.durable(order.queue).withArgument(x-dead-letter-exchange,order.dlx.exchange)// 指定死信交换机.withArgument(x-dead-letter-routing-key,order.dlx.routing.key)// 死信路由键.withArgument(x-message-ttl,10000)// 消息TTL 10秒测试用.withArgument(x-max-length,5)// 队列最大长度5条.build();}// 死信队列BeanpublicQueueorderDlq(){returnQueueBuilder.durable(order.dlq).build();}// 绑定原业务交换机 ↔ 原业务队列BeanpublicBindingorderBinding(){returnBindingBuilder.bind(orderQueue()).to(orderExchange()).with(order.routing.key);}// 绑定死信交换机 ↔ 死信队列BeanpublicBindingdlqBinding(){returnBindingBuilder.bind(orderDlq()).to(orderDlxExchange()).with(order.dlx.routing.key);}}3. 延迟队列插件方式配置示例首先确保已安装 RabbitMQ 延迟插件rabbitmq-pluginsenablerabbitmq_delayed_message_exchange延迟队列配置类importorg.springframework.amqp.core.*;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.HashMap;importjava.util.Map;ConfigurationpublicclassDelayedQueueConfig{// 自定义延迟交换机类型publicstaticfinalStringDELAYED_EXCHANGE_TYPEx-delayed-message;// 延迟交换机BeanpublicCustomExchangedelayedExchange(){MapString,ObjectargsnewHashMap();args.put(x-delayed-type,direct);// 底层仍是 direct 类型returnnewCustomExchange(order.delayed.exchange,DELAYED_EXCHANGE_TYPE,true,// 持久化false,// 不自动删除args);}// 延迟队列BeanpublicQueuedelayedQueue(){returnQueueBuilder.durable(order.delayed.queue).build();}// 绑定延迟交换机与队列BeanpublicBindingdelayedBinding(){returnBindingBuilder.bind(delayedQueue()).to(delayedExchange()).with(order.delayed.routing.key).noargs();}}4. 生产者示例importorg.springframework.amqp.core.Message;importorg.springframework.amqp.core.MessageProperties;importorg.springframework.amqp.rabbit.core.RabbitTemplate;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importjava.nio.charset.StandardCharsets;ComponentpublicclassOrderProducer{AutowiredprivateRabbitTemplaterabbitTemplate;/** * 发送普通订单消息可能进入死信队列 */publicvoidsendOrderMessage(StringorderId){Stringmessage订单创建orderId;rabbitTemplate.convertAndSend(order.exchange,order.routing.key,message,msg-{// 设置消息属性msg.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);returnmsg;});System.out.println(发送订单消息message);}/** * 发送延迟消息30分钟后取消订单 */publicvoidsendDelayedCancelMessage(StringorderId){Stringmessage订单取消检查orderId;MessagePropertiespropsnewMessageProperties();props.setDelay(30*60*1000);// 延迟30分钟毫秒props.setDeliveryMode(MessageDeliveryMode.PERSISTENT);MessagemsgnewMessage(message.getBytes(StandardCharsets.UTF_8),props);rabbitTemplate.send(order.delayed.exchange,order.delayed.routing.key,msg);System.out.println(发送延迟取消消息30分钟后生效message);}}5. 消费者示例importcom.rabbitmq.client.Channel;importorg.springframework.amqp.core.Message;importorg.springframework.amqp.rabbit.annotation.RabbitListener;importorg.springframework.stereotype.Component;importjava.io.IOException;ComponentpublicclassOrderConsumer{/** * 监听原业务队列 */RabbitListener(queuesorder.queue)publicvoidhandleOrderMessage(Messagemessage,Channelchannel)throwsIOException{StringmsgnewString(message.getBody());System.out.println(收到订单消息msg);try{// 模拟业务处理processOrder(msg);// 处理成功手动ACKchannel.basicAck(message.getMessageProperties().getDeliveryTag(),false);System.out.println(订单处理成功已ACK);}catch(Exceptione){System.err.println(订单处理失败e.getMessage());// 处理失败拒绝消息并进入死信队列channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,// 不批量拒绝false// requeuefalse不重新入队进入死信);System.out.println(消息已拒绝将进入死信队列);}}/** * 监听死信队列用于监控和补偿 */RabbitListener(queuesorder.dlq)publicvoidhandleDlqMessage(Messagemessage,Channelchannel)throwsIOException{StringmsgnewString(message.getBody());System.err.println(⚠️ 收到死信消息msg);System.err.println(死信原因message.getMessageProperties().getHeaders());// 记录日志、发送告警、人工介入等sendAlert(msg);// 确认消费死信队列消息通常只记录不重试channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);}/** * 监听延迟队列 */RabbitListener(queuesorder.delayed.queue)publicvoidhandleDelayedMessage(Messagemessage,Channelchannel)throwsIOException{StringmsgnewString(message.getBody());System.out.println(⏰ 延迟消息生效msg);// 执行延迟任务如取消订单cancelOrder(msg);channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);}privatevoidprocessOrder(StringorderMsg)throwsException{// 模拟业务逻辑if(orderMsg.contains(error)){thrownewRuntimeException(模拟业务处理异常);}// 正常处理...}privatevoidsendAlert(StringdlqMsg){// 发送邮件/钉钉/短信告警System.err.println(发送告警dlqMsg);}privatevoidcancelOrder(StringorderMsg){// 执行订单取消逻辑System.out.println(执行订单取消orderMsg);}}6. 测试控制器importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;RestControllerRequestMapping(/order)publicclassOrderController{AutowiredprivateOrderProducerorderProducer;PostMapping(/create)publicStringcreateOrder(RequestParamStringorderId){orderProducer.sendOrderMessage(orderId);return订单创建消息已发送orderId;}PostMapping(/create-with-delay)publicStringcreateOrderWithDelay(RequestParamStringorderId){orderProducer.sendOrderMessage(orderId);orderProducer.sendDelayedCancelMessage(orderId);return订单创建延迟取消消息已发送orderId;}PostMapping(/test-error)publicStringtestError(RequestParamStringorderId){// 发送会触发死信的消息orderProducer.sendOrderMessage(orderId-error);return测试异常消息已发送将进入死信队列;}}7. 运行测试步骤启动 RabbitMQ 并安装延迟插件rabbitmq-pluginsenablerabbitmq_delayed_message_exchange启动 Spring Boot 应用mvn spring-boot:run测试死信队列# 发送正常消息curl-XPOSThttp://localhost:8080/order/create?orderId123# 发送会触发死信的消息curl-XPOSThttp://localhost:8080/order/test-error?orderId456测试延迟队列# 发送订单并设置30分钟后自动取消curl-XPOSThttp://localhost:8080/order/create-with-delay?orderId7898. 关键点说明死信触发条件代码中通过basicNack(requeuefalse)模拟消费者处理失败消息将进入死信队列。延迟消息使用rabbitmq-delayed-message-exchange插件通过setDelay()方法设置延迟时间。监控建议死信队列应配置监控告警延迟队列可记录消息发送和消费时间戳建议添加消息轨迹追踪生产环境优化配置连接池和重试机制添加消息序列化/反序列化异常处理考虑使用消息中间件管理平台这个完整示例展示了死信交换机和延迟队列的实际应用可以直接复制到项目中运行测试。
RELATED

相关推荐

【AI编程×敏捷开发终极融合指南】:20年架构师亲授5大落地陷阱与3周提速实战框架

【AI编程×敏捷开发终极融合指南】:20年架构师亲授5大落地陷阱与3周提速实战框架

更多请点击: https://intelliparadigm.com 第一章:AI编程敏捷开发融合的认知革命 当Copilot在结对编程中实时补全用户故事验收条件,当LLM自动生成Sprint回顾会议纪要并提炼技术债趋势,敏捷开发的“个体与互动高于流程与工具”原…

📅 2026/9/28 17:37:55
CVAT完整指南:3分钟部署开源计算机视觉数据标注平台

CVAT完整指南:3分钟部署开源计算机视觉数据标注平台

CVAT完整指南:3分钟部署开源计算机视觉数据标注平台 【免费下载链接】cvat Computer Vision Annotation Tool (CVAT) is a leading platform for building high-quality visual datasets for vision AI. It offers open-source, cloud, and enterprise products, as…

📅 2026/8/22 22:04:27
嵌入式多媒体内存加速:DMM/TILER硬件引擎原理与优化实践

嵌入式多媒体内存加速:DMM/TILER硬件引擎原理与优化实践

1. 项目概述:DMM/TILER——嵌入式多媒体系统的内存加速引擎 在嵌入式多媒体处理领域,尤其是视频编解码、图形渲染和图像处理,我们常常面临一个核心矛盾:处理器和专用加速器(如视频编解码器、GPU)的计算能力…

📅 2026/9/10 3:19:02
MORE NEWS

更多资讯

📰

TwinCAT3安装与激活完整指南:从环境准备到第一个PLC项目

1. TwinCAT3安装前的整体规划与思路拆解1.1 为什么TwinCAT3的安装值得单独写一篇完整指南搞工业自动化的朋友对TwinCAT3应该不陌生,它是基于PC的控制平台,把PLC、运动控制、HMI、甚至机器视觉都集成到了一套Visual Studio Shell环境里。但很多人第一次装…

📰

J-Link报defective?驱动与固件版本冲突排查修复指南

1. 从一次深夜调试说起:那块“变砖”的J-Link凌晨两点,我盯着Keil的下载窗口,弹出来的不是熟悉的“Programming Done”,而是一行红字:The connected J-Link is defective。手边这块J-Link用了三年,前一天还…

📰

Ubuntu 22.04下Intel WiFi驱动问题全解决:从固件安装到网络调优

1. 项目背景与核心需求拆解1.1 为什么Ubuntu 22.04下Intel WiFi驱动总出问题如果你刚装完Ubuntu 22.04,发现右上角网络图标里压根没有WiFi选项,或者能看到WiFi列表但死活连不上,大概率不是硬件坏了,而是驱动没到位。Ubuntu 22.04 …

📰

Agent-native架构:从AI补丁到智能体原生的工程实践

最近,我在技术社群里反复看到 agent-native 这个词。说实话,第一次听到的时候,我以为是给“智能体”换了个营销外壳,直到认真拆了几套系统,又动手改造了一个真实的业务流程以后,才发现它背后藏着一个相当本…

📰

Wi-Fi 6 AX调度全解析:OFDMA、MU-MIMO与TWT实战指南

前阵子做 Wi-Fi 6 项目验收,客户网管跟我提了个词:AX 调度。他说网上讲得都太零散,想知道这个调度到底调度了什么、开了之后有没有用、为什么自己的 AP 开了某些开关后终端反而掉线。这其实正好戳到 802.11ax(Wi-Fi 6)…

📰

SystemVerilog双向开关tran与tranif1选型指南:从仿真异常到建模实践

1. 从一个仿真波形异常说起:为什么需要搞懂tran和tranif1几年前我在做一个混合信号芯片的验证平台,DUT里有一组模拟开关阵列,前后级电路通过双向端口互联。当时为了图省事,在testbench里用tran原语搭了几个双向通路,结…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬