RabbitMQ死信队列

在Spring Boot中,死信队列(Dead-Letter Queue, DLQ)通常与RabbitMQ等消息中间件结合使用,用于处理无法被正常消费的消息(如消息过期、消费失败或队列达到最大长度)。以下是实现死信队列的核心步骤和示例:


1. 核心概念

  • 死信队列:存储被拒绝(Rejected)、过期(TTL)或队列达到最大长度时未消费的消息的特殊队列。
  • 死信交换机(DLX):绑定死信队列的交换机,用于接收死信消息。
  • 绑定关系:正常队列通过参数指定死信交换机和路由键,将死信转发到DLQ。

2. Spring Boot 配置步骤

2.1 添加依赖

    org.springframework.boot
    spring-boot-starter-amqp


2.2 配置RabbitMQ连接

yaml
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

2.3 声明正常队列和死信队列

java
@Configuration
public class RabbitMQConfig {

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

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

    @Bean
    public Binding dlxBinding() {
        return BindingBuilder.bind(dlxQueue())
                .to(dlxExchange()).with("dlx.routing.key");
    }

    // 声明正常队列,绑定死信交换机
    @Bean
    public Queue normalQueue() {
        return QueueBuilder.durable("normal.queue")
                .withArgument("x-dead-letter-exchange", "dlx.exchange")  // 指定死信交换机
                .withArgument("x-dead-letter-routing-key", "dlx.routing.key")  // 指定死信路由键
                .build();
    }

    @Bean
    public DirectExchange normalExchange() {
        return new DirectExchange("normal.exchange");
    }

    @Bean
    public Binding normalBinding() {
        return BindingBuilder.bind(normalQueue())
                .to(normalExchange()).with("normal.routing.key");
    }
}


3. 触发死信的场景

3.1 消息被拒绝(Requeue=false)
java
@RabbitListener(queues = "normal.queue")
public void handleMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
    try {
        // 业务逻辑处理
        if (/* 处理失败 */) {
            channel.basicNack(tag, false, false);  // 拒绝消息,不重新入队
        }
    } catch (Exception e) {
        channel.basicReject(tag, false);  // 拒绝消息,不重新入队
    }
}

3.2 消息过期(TTL)

java
// 声明队列时设置TTL(单位:毫秒)
@Bean
public Queue ttlQueue() {
    return QueueBuilder.durable("ttl.queue")
            .withArgument("x-dead-letter-exchange", "dlx.exchange")
            .withArgument("x-dead-letter-routing-key", "dlx.routing.key")
            .withArgument("x-message-ttl", 10000)  // 10秒后过期
            .build();
}

3.3 队列达到最大长度

java
// 声明队列时设置最大长度
@Bean
public Queue maxLengthQueue() {
    return QueueBuilder.durable("max.queue")
            .withArgument("x-dead-letter-exchange", "dlx.exchange")
            .withArgument("x-dead-letter-routing-key", "dlx.routing.key")
            .withArgument("x-max-length", 100)  // 最大长度100
            .build();
}


4. 监听死信队列

java
@RabbitListener(queues = "dlx.queue")
public void handleDeadLetter(String message) {
    // 处理死信消息(如记录日志、人工干预等)
    System.out.println("Received dead letter: " + message);
}


5. 测试流程

  1. 发送消息到正常队列:
    java
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendMessage() {
        rabbitTemplate.convertAndSend("normal.exchange", "normal.routing.key", "Hello, DLQ!");
    }
  2. 触发死信条件(如拒绝消息或等待TTL过期)。
  3. 观察死信队列是否接收到消息。

6. 注意事项

  • 交换机和队列声明顺序:确保死信交换机和队列先于正常队列声明。
  • 路由键匹配:死信消息的路由键需与死信队列的绑定键一致。
  • 幂等性处理:死信队列中的消息可能需要重试,需设计幂等逻辑避免重复处理。

通过以上步骤,您可以在Spring Boot中实现基于RabbitMQ的死信队列机制,提升消息系统的可靠性。

你可能感兴趣的:(rabbitmq,分布式)