RabbitMQ死信队列

一、什么是死信队列

消息无法被正常消费,被 broker 判定为失效消息 ,不会继续留在原队列等待重试,转而投递到预先绑定的队列,这个专门接收失效消息的队列就是死信队列

消息变成死信的三种核心场景

  1. 消费者拒绝消息
    • basicNack / basicReject,并且设置 requeue=false(不重新放回原队列); 手动业务异常,主动拒收消息,不重试。
  2. 消息超时(TTL 过期)
    • 消息本身设置过期时间;
    • 队列设置全局消息过期时间; 消息一直未被消费,超时自动沦为死信。
  3. 队列达到最大长度 队列堆积消息数量超过 x-max-length 上限,队尾多余消息被丢弃转入死信。

死信队列不是特殊类型队列,只是普通队列,依靠**死信交换机 DLX(Dead Letter Exchange)**实现路由转发。

二、核心组件:DLX 死信交换机

  1. 原业务队列 配置两个参数:
    • x-dead-letter-exchange:指定死信交换机名称;
    • x-dead-letter-routing-key:死信转发时使用的路由键(可选,默认沿用原消息 routingKey);
  2. 消息判定为死信后,RabbitMQ 会自动将这条消息重新发送到 DLX,DLX 根据路由键投递到绑定的死信队列。

整体流转链路:

复制代码
生产者 → 普通交换机 → 业务队列 → 消费失败/超时/队列满
→ broker自动转发 → DLX死信交换机 → 死信队列DLQ

三、常用配置方式

方式 1:创建业务队列时绑定 DLX(最常用)

1)界面管理端配置

创建队列时添加 Arguments:

参数键 说明
x-dead-letter-exchange 填写提前建好的死信交换机名称
x-dead-letter-routing-key 死信路由键,自定义
x-message-ttl 队列全局消息过期时间,单位 ms
x-max-length 队列最大消息条数
2)Java SpringBoot 代码示例
复制代码
// 1.声明死信交换机
@Bean
public DirectExchange deadLetterExchange() {
    return ExchangeBuilder.directExchange("dlx.exchange").durable(true).build();
}

// 2.声明死信队列
@Bean
public Queue deadLetterQueue() {
    return QueueBuilder.durable("dlq.queue").build();
}

// 3.绑定死信交换机与死信队列
@Bean
public Binding deadLetterBinding() {
    return BindingBuilder.bind(deadLetterQueue())
            .to(deadLetterExchange())
            .with("dl.routing.key");
}

// 4.业务队列绑定死信交换机配置
@Bean
public Queue businessQueue() {
    return QueueBuilder.durable("business.queue")
            // 指定死信交换机
            .withArgument("x-dead-letter-exchange", "dlx.exchange")
            // 指定死信路由key
            .withArgument("x-dead-letter-routing-key", "dl.routing.key")
            // 可选:消息30秒超时未消费则进死信
            .withArgument("x-message-ttl", 30000)
            .build();
}

四、典型业务使用场景

1. 消费失败兜底处理

业务处理异常(数据库异常、第三方接口报错),不无限重试:

  • 消费者捕获异常,执行 nack(requeue=false)
  • 消息进入死信队列,人工排查问题后重新投递。

2. 延迟队列(经典实现方案)

利用 TTL + 死信间接实现延迟:

  1. 消息先进入设置 TTL 的临时队列,无消费者;
  2. 消息超时自动转入 DLX,路由到目标业务队列;
  3. 消费者监听目标队列,达到定时消费效果。

局限:同一队列 TTL 必须一致,高精度延迟建议使用 RabbitMQ 延迟插件。

3. 防止消息无限堆积

限制业务队列最大消息数,流量突增打爆队列时溢出消息进入死信,避免服务雪崩。

五、死信队列标准运维方案

  1. 独立消费者监听死信队列 专门消费死信消息,记录日志、入库标记异常订单 / 任务,发送告警(钉钉 / 邮件);
  2. 死信重试策略
  • 方案 A:人工修复问题后,将死信消息重新发送至原业务交换机;
  • 方案 B:延时重试:死信接收后暂存 Redis,间隔一段时间重新投递,多次失败后永久归档;
  1. 死信消息留存 死信队列尽量不自动删除,保留数据用于问题溯源,定期归档清理。

六、容易踩坑的常见问题

  1. nack requeue=true 不会进死信 消息只是重回原队列头部,反复重试,极易死循环堆积,业务异常务必 requeue=false
  2. 死信交换机必须提前创建 如果业务队列配置的 DLX 不存在,死信消息会直接被丢弃;
  3. 死信消息携带原有属性 原消息的 headers、body、routingKey 都会保留,同时新增死信原因标识;
  4. 队列 TTL 和消息 TTL 优先级 消息发送时设置的expiration优先级 > 队列配置的x-message-ttl

七、简易工作流程示例

  1. 生产者发送消息到 business.exchangebusiness.queue
  2. 消费者处理报错,channel.basicNack(deliveryTag, false, false)
  3. RabbitMQ 检测到拒收且不重回队列,转发消息到 dlx.exchange
  4. DLX 根据路由键把消息投递至 dlq.queue
  5. 运维 / 专门消费者监听 dlq.queue,打印日志、触发告警,排查问题后重投。
相关推荐
long3161 小时前
Java 团队入门到精通学习资料
java·开发语言
vx-程序开发1 小时前
【java项目分享】springboot农产品销售平台14952
java·javascript·spring boot·python·eclipse·django·php
软件测试媛1 小时前
软件测试面试问题汇总
功能测试·面试·职场和发展·压力测试
武子康1 小时前
开放权重不是唯一控制权:Kimi K3、Tencent Hy3 与 ByteDance Seed 的九项交付比较
人工智能·llm·agent
城管不管2 小时前
rabbitmq如何保证消息不丢失?解决方案又是什么?
开发语言·ai·面试·职场和发展·rabbitmq·php·agent
程序员良辰2 小时前
【TongWeb7】启动接近两分钟问题排查
java·开发语言·中间件
八角.。2 小时前
Java案例-学生管理系统
java
2601_956456342 小时前
从研发到交付:嗨动视觉分布式KVM坐席系统的靠谱逻辑
分布式
盖伦发发2 小时前
AIE-AI Engineering三, 四章总结: 如何评估AI应用
人工智能·ai