一、死信队列
死信指的是无法被消费的消息,由于消息TTL过期、队列达到最大长度、消息被拒绝等原因,导致队列中一些消息无法被消费,这样的消息如果没有进行后续的处理,就会变成死信。为了保证消息数据不丢失,需要使用死信队列机制。
二、死信队列的实现
1、消息 TTL
过期
普通队列消费者Consumer01
public class Consumer01 {
//不同交换机
public static final String NORMAL_EXCHANGE = "normal_exchange";
//死信交换机
public static final String DEAD_EXCHANGE = "dead_exchange";
//普通队列
public static final String NORMAL_QUEUE = "normal_queue";
//死信队列
public static final String DEAD_QUEUE = "dead_queue";
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-message-ttl","10000"); //设置TTL过期时间为10s
arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE); //给普通队列设置死信交换机
arguments.put("x-dead-letter-routing-key", "lisi"); //设置死信交换机的routingKey
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("Consumer01等待接收消息......");
//声明接收消息回调函数 和 取消消息消费时的回调函数
DeliverCallback deliverCallback = (consumerTag, message) -> {
String msg = new String(message.getBody(), "UTF-8");
System.out.println("Consumer01接收消息:" + msg);
};
CancelCallback cancelCallback = (consumerTag) -> {
System.out.println("取消消息消费");
};
channel.basicConsume(NORMAL_QUEUE, true, deliverCallback, cancelCallback);
}
}
死信队列消费者Consumer02
public class Consumer02 {
//死信队列
public static final String DEAD_QUEUE = "dead_queue";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
System.out.println("Consumer02等待接收消息......");
//声明接收消息回调函数 和 取消消息消费时的回调函数
DeliverCallback deliverCallback = (consumerTag, message) -> {
String msg = new String(message.getBody(), "UTF-8");
System.out.println("Consumer02接收消息:" + msg);
};
CancelCallback cancelCallback = (consumerTag) -> {
System.out.println("取消消息消费");
};
channel.basicConsume(DEAD_QUEUE, true, deliverCallback, cancelCallback);
}
}
生产者设置TTL
消息过期时间为10s
public class Producer {
public static final String NORMAL_EXCHANGE = "normal_exchange";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//设置TTL消息过期时间
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();
for (int i = 0; i <= 10; i++) {
String message = "info" + i;
channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", properties, message.getBytes("UTF-8"));
}
}
}
在普通队列挂掉了的情况下,由于设置TTL为10s,超时之后消息会通过死信交换机被发送到死信队列
死信队列消费者会接收了死信队列的消息
2、队列达到最大长度
普通队列长度设置为5,超过最大长度的消息会被放到死信队列中
生产者一共发送了11条消息,5条消息在普通队列,6条消息在死信队列
3、消息被拒绝
如果普通消费者拒绝掉普通队列里面的消息,消息也会被放到死信队列中
普通消费者拒绝的消息被转发到死信队列
拒绝的消息被死信消费者接收