RabbitMQ学习笔记 - 死信队列

参考:<>

Dead-Letter-Exchange,简称DLX,可称为死信交换器、死信邮箱等等。

当消息在一个队列中变成死信(dead message)之后,它能被重新发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就称之为死信队列

消息变成死信的几种情况:

  • 消息被拒绝(Basic.Reject/Basic.Nack),并且设置requeue参数为false
  • 消息过期
  • 队列到达最大长度

注:

  • DLX也是一个正常的交换器,和一般的交换器没有区别,它能在任何队列上被指定,实际上就是设置某个队列的属性。
  • 当这个队列中存在死信时,RabbitMQ就会自动地将这个消息重新发布到设置的DLX上去,进而被路由到另一个队列,即死信队列。可以监听这个队列中的消息、以进行相应的处理。
  • 通过在channel.QueueDeclare方法中设置x-dead-letter-exchange参数来为这个队列添加DLX。

示例:

1. 原生api

声明了两个交换器 dlxExchangeName和normalExchangeName,分别绑定了两个队列dlxQueue和normalQueue。发送消息流程:

  • 生产者首先发送一条携带路由键为normalRoutingKey的消息
  • 经过交换器normalExchangeName将消息存储到normalQueue中
  • 队列设置了消息的过期时间为5s,在这5s内没有消费者消费这条消息,那么这条消息就被判定为过期
  • 由于设置了DLX,消息过期之后就会被转发到dlxExchangeName中,这时消息被存储到绑定的dlxQueue中,也就是这个死信队列中
...

// 死信交换器、队列
channel.exchangeDeclare(dlxExchangeName, "direct", true);
channel.queueDeclare(dlxQueueName, true, false, false, null);
channel.queueBind(dlxQueue, dlxExchangeName, dlxRoutingKey);

// 普通交换器、队列
channel.exchangeDeclare(normalExchangeName, "direct", true);
Map<String, Object> arguments = new HashMap<>(4);
arguments.put("x-message-ttl", 5000);// 设置消息过期时间
arguments.put("x-dead-letter-exchange", dlxExchangeName);// 为普通队列添加DLX
arguments.put("x-dead-letter-routing-key", dlxRoutingKey);// 为这个DLX指定路由键,不指定则使用原队列的路由键
channel.queueDeclare(queueName, true, false, false, arguments);
channel.queueBind(normalQueue, normalExchangeName, normalRoutingKey);

byte[] content = "Test Msg".getBytes("UTF-8");
channel.basicPublish(normalExchangeName, normalRoutingKey, false, null, content);

...

进入Web管理页面,创建的队列如下图所示:
队列属性说明

  • D:durable的缩写,设置了队列的持久化
  • TTL:设置了过期时间
  • DLX:这个队列设置了死信交换器
  • DLK:指的是x-dead-letter-routing-key这个属性

2. springboot

(1)声明交换器、队列
和原生api一样,在声明队列时指定DLX,通过设置消息过期时间模拟。

@Bean
public DirectExchange dlxNormalExchange() {
    return new DirectExchange(normalExchangeName);
}

@Bean
public Queue dlxNormalQueue() {
    Map<String, Object> args = new HashMap<>(4);
    // 设置消息过期时间
    args.put("x-message-ttl", 5000);
    // 为普通队列添加DLX
    args.put("x-dead-letter-exchange", dlxExchangeName);
    // 为这个DLX指定路由键,不指定则使用原队列的路由键
    args.put("x-dead-letter-routing-key", dlxRoutingKey);
    return new Queue(normalQueueName, true, false, false, args);
}

@Bean
Binding bindingDlxNormalQueue(Queue dlxNormalQueue, DirectExchange dlxNormalExchange) {
    return BindingBuilder.bind(dlxNormalQueue).to(dlxNormalExchange).with(normalRoutingKey);
}

@Bean
public DirectExchange dlxExchange() {
    return new DirectExchange(dlxExchangeName);
}

@Bean
public Queue dlxQueue() {
    // true 持久化
    return new Queue(dlxQueueName, true);
}

@Bean
Binding bindingDlxQueue(Queue dlxQueue, DirectExchange dlxExchange) {
    return BindingBuilder.bind(dlxQueue).to(dlxExchange).with(dlxRoutingKey);
}

(2)测试发送消息
正常发送消息即可,不需要设置其他消息属性。

springboot-rabbitmq-demo测试代码:https://github.com/mytt-10566/springboot-rabbitmq-demo

你可能感兴趣的:(rabbitmq)