基于本文回答
0
评论

RabbitMQ 的死信队列(DLX)

知识点图片

死信队列用于存储无法正常消费的消息(超时、被拒、队列满),常用于实现延迟队列和异常兜底处理。

RabbitMQ 死信队列 (DLX) 详解

死信交换机(Dead Letter Exchange,简称 DLX)是 RabbitMQ 中一种处理无法被正常消费消息的机制。当消息在一个队列中变成“死信”之后,它会被重新发送到另一个交换机中,这个交换机就是 DLX,绑定到 DLX 的队列称为死信队列

1. 消息变成“死信”的三种情况

消息在以下三种情况下会触发 DLX 机制:

  1. 消息被拒绝 (Rejected)
    • 消费者使用 basic.rejectbasic.nack 拒绝消息。
    • 并且参数 requeue 设置为 false(不重新入队)。
  2. 消息过期 (TTL Expired)
    • 消息在队列中的存活时间超过了设置的 TTL(Time To Live),导致过期。
  3. 队列达到最大长度 (Queue Limit)
    • 队列的消息数量已经达到了最大长度限制,最早的消息会被挤出队列。

2. 运行流程图解

plaintext
[生产者] 
   ↓ 发送消息
[正常交换机]
   ↓ 路由
[正常队列]  <-- (配置了 x-dead-letter-exchange)
   ↓
   ↓ (消息变成死信:过期/被拒/队列满)
   ↓
[死信交换机 (DLX)]
   ↓ 路由
[死信队列]
   ↓
[死信消费者] (处理延迟任务或记录异常)

3. 如何配置

死信队列的配置实际上是在正常队列声明时,通过添加参数(Arguments)来绑定的:

  • x-dead-letter-exchange: 指定死信交换机的名称(必须)。
  • x-dead-letter-routing-key: 指定发送到 DLX 时的路由键(可选,如果不填则默认使用原消息的路由键)。

Java (Spring AMQP) 示例代码片段:

java
// 1. 声明死信交换机和死信队列
@Bean
public DirectExchange deadLetterExchange() {
    return new DirectExchange("dlx.exchange");
}

@Bean
public Queue deadLetterQueue() {
    return new Queue("dlx.queue");
}

// 2. 声明正常队列,并绑定死信交换机
@Bean
public Queue normalQueue() {
    Map<String, Object> args = new HashMap<>();
    // 绑定死信交换机
    args.put("x-dead-letter-exchange", "dlx.exchange");
    // (可选) 修改死信的路由键
    args.put("x-dead-letter-routing-key", "dlx.routing.key");
    // (可选) 设置队列最大长度或消息过期时间
    args.put("x-message-ttl", 10000); // 10秒过期

    return QueueBuilder.durable("normal.queue")
            .withArguments(args)
            .build();
}

4. 核心应用场景

  1. 延迟队列 (Delay Queue)

    • 原理:RabbitMQ 原生不支持延迟队列。通过设置消息的 TTL(例如 30 分钟),并将消息发送到一个没有消费者的正常队列。当消息过期后,自动转发到死信队列,消费者监听死信队列即可实现“延迟 30 分钟处理”。
    • 场景:订单超时未支付自动取消、注册后延迟发送短信等。
  2. 异常兜底与重试

    • 原理:当消费者处理消息多次失败后,拒绝该消息(requeue=false),消息进入死信队列。
    • 场景:防止毒丸消息(Poison Pill)阻塞主队列,将问题消息转移到死信队列进行人工排查或独立的补偿逻辑处理。
右滑查看面试常问