死信队列(Dead Letter Queue, DLQ)是消息队列中的一种特殊机制。正常情况下,消息会被直接消费,但由于以下几个原因,消息可能会被转移到死信队列中:
basic.reject
或basic.nack
)并且不重回队列。死信队列的主要作用是用来处理那些无法被正常消费的消息,确保系统的健壮性。
如上图所示,正常的消息会进入C1
消费者进行处理,但由于某些原因(例如超时、拒绝等),部分消息被转入了死信队列,并最终由C2
消费者进行处理。
package com.lucifer.rabbitmq.DeadLetterQueue;
import com.lucifer.rabbitmq.utils.RabbitMqUtils;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import java.util.HashMap;
import java.util.Map;
public class Consumer1 {
public static final String normal_exchange = "normal_exchange0";
public static final String dead_exchange = "dead_exchange0";
public static final String normal_queue = "normal_queue0";
public static final String dead_queue = "dead_queue0";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
// 声明交换机
channel.exchangeDeclare(normal_exchange, BuiltinExchangeType.DIRECT);
channel.exchangeDeclare(dead_exchange, BuiltinExchangeType.DIRECT);
// 声明队列并设置参数
Map<String, Object> arguments = new HashMap<>();
// 设置死信交换机
arguments.put("x-dead-letter-exchange", dead_exchange);
// 设置死信路由键
arguments.put("x-dead-letter-routing-key", "lisi");
// 设置消息TTL(过期时间为10秒)
arguments.put("x-message-ttl", 10000);
// 声明正常队列
channel.queueDeclare(normal_queue, false, false, false, arguments);
// 声明死信队列
channel.queueDeclare(dead_queue, false, false, false, null);
// 绑定队列到交换机
channel.queueBind(normal_queue, normal_exchange, "zhangsan");
channel.queueBind(dead_queue, dead_exchange, "lisi");
System.out.println("等待接收消息...");
// 消费消息
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("Consumer1 接收到的消息:" + new String(message.getBody()));
};
channel.basicConsume(normal_queue, true, deliverCallback, consumerTag -> {});
}
}
package com.lucifer.rabbitmq.DeadLetterQueue;
import com.lucifer.rabbitmq.utils.RabbitMqUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
public class Consumer2 {
public static final String dead_queue = "dead_queue0";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
System.out.println("等待接收死信消息...");
// 消费死信队列消息
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("Consumer2 接收到的死信消息:" + new String(message.getBody()));
};
channel.basicConsume(dead_queue, true, deliverCallback, consumerTag -> {});
}
}
package com.lucifer.rabbitmq.DeadLetterQueue;
import com.lucifer.rabbitmq.utils.RabbitMqUtils;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
public class Producer {
public static final String normal_exchange = "normal_exchange0";
public static final String dead_exchange = "dead_exchange0";
public static final String normal_queue = "normal_queue0";
public static final String dead_queue = "dead_queue0";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
// 设置10秒的TTL(过期时间)
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();
// 发送10条消息
for (int i = 0; i < 10; i++) {
String message = "info" + i;
channel.basicPublish(normal_exchange, "zhangsan", properties, message.getBytes());
System.out.println("发送消息:" + message);
}
}
}
normal_queue0
队列中消费消息,该队列设置了一个死信交换机和路由键。当消息超时后会转入死信队列。dead_queue0
死信队列中消费死信消息。normal_exchange0
发送消息,并指定消息的TTL(10秒),当消息在规定时间内没有被消费时,会被转入死信队列。通过这套机制,可以有效处理那些在业务逻辑中无法正常消费的消息。