概念
死信队列(Dead Letter Queue, DLQ)是一种用于处理消息队列中未被成功消费或处理失败的消息的机制。消息在传递过程中可能因为多种原因未被正常处理(例如消费者拒绝消费、消息处理超时、消息格式错误等),这些消息被称为“死信”。
代码架构图(截图尚硅谷RabbitMQ课程)
由架构图可以看出来,死信队列就是在原队列上绑定一个新的队列,这个队列负责处理失败的消息。其与之前提到的队列最大的区别我个人觉得是在设置普通交换机的时候传入参数来绑定死信队列。
产生死信的三种情况
-
消息TTL过期
-
队列长度限制
-
消息被拒绝(basic.nack)requeue = false
情况一:消息TTL过期
在普通队列的基础上增加了特定的绑定参数超时时间。
//声明普通交换机
channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
Map<String, Object> arguments = new HashMap<>();
//设置超时时间
arguments.put("x-dead-letter-ttl", 10000);
//设置死信交换机
arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
//设置死信RoutingKey
arguments.put("x-dead-letter-routing-key", "lisi");
channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments);
channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "zhangsan");
模拟超时环境,先启动上面消费者声明,然后停掉消费者并等待超时,超时后开启生产者发送消息。
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();
for (int i = 1; i < 11; i++) {
String message = "info" + i;
channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",properties,message.getBytes(StandardCharsets.UTF_8));
}
情况二:队列长度限制
//设置死信交换机
arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
//设置死信RoutingKey
arguments.put("x-dead-letter-routing-key", "lisi");
//设置长度限制
arguments.put("x-max-length", 6);
channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments);
channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "zhangsan");
把超时时间删除,换成长度限制为6,通过发送十条消息,把余下的消息放入死信队列。但是因为我这里实验环境有限,先关闭消费者1,这时候他知道自己需要卡六个名额,但是没有数据,然后打开生产者,进入十条数据,这时候队列超过最大长度消息溢出,进入死信队列的是最先进入队列的。(哭了,这块卡了我二十多分钟不知道为什么死信队列出来的是1234);
情况三:消息被拒绝
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String msg = new String(delivery.getBody(), StandardCharsets.UTF_8);
if(msg.equals("info5")){
System.out.println("Consumer1接收到的消息:" + msg+"拒绝了");
channel.basicReject(delivery.getEnvelope().getDeliveryTag(), false);
}else{
System.out.println("Consumer1接收到的消息:" + msg);
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
};
channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, consumerTag -> {});
把自动应答设置为false,设置当info5时候拒绝消息,不放回放入死信队列