死信队列的概念
死信(dead message)简单理解就是因为种种原因,无法被消费的信息,就是死信。
有死信,自然就有死信队列。当消息在⼀个队列中变成死信之后,它能被重新被发送到另⼀个交换器中,这个交换器就是DLX( Dead Letter Exchange ),绑定DLX的队列,就称为死信队列(Dead Letter Queue,简称DLQ)。
如图所示工作机制:
消息变成死信⼀般是由于以下几种情况:
1. 消息被拒绝( Basic.Reject/Basic.Nack ),并且设置 requeue 参数为false。
2. 消息过期。
3. 队列达到最大长度。
4. 消息发生异常。
代码案例
声明队列和交换机
包含两部分:
• 声明正常的队列和正常的交换机
• 声明死信队列和死信交换机
死信交换机和死信队列和普通的交换机,队列没有区别。
如代码:
//常量类//死信队列 public static final String DLX_EXCHANGE_NAME = "dlx_exchange";public static final String DLX_QUEUE = "dlx_queue";//普通队列public static final String NORMAL_EXCHANGE_NAME = "normal_exchange";public static final String NORMAL_QUEUE = "normal_queue";
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import rabbitmq.Constant;/*** 死信队列相关配置 */@Configurationpublic class DLXConfig {//死信交换机 @Bean("dlxExchange")public Exchange dlxExchange(){return ExchangeBuilder.topicExchange(Constant.DLX_EXCHANGE_NAME).durable(true).build();}//2. 死信队列 @Bean("dlxQueue")public Queue dlxQueue() {return QueueBuilder.durable(Constant.DLX_QUEUE).build();}//3. 死信队列和交换机绑定 Binding @Bean("dlxBinding")public Binding dlxBinding(@Qualifier("dlxExchange") Exchange exchange,
@Qualifier("dlxQueue") Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("dlx").noargs();
}//正常交换机 @Bean("normalExchange")public Exchange normalExchange(){return ExchangeBuilder.topicExchange(Constant.NORMAL_EXCHANGE_NAME).durable(true).build();}//正常队列 @Bean("normalQueue")public Queue normalQueue() {return QueueBuilder.durable(Constant.NORMAL_QUEUE).build();}//正常队列和交换机绑定 Binding @Bean("normalBinding")public Binding normalBinding(@Qualifier("normalExchange") Exchange exchange, @Qualifier("normalQueue") Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("normal").noargs();}
}
正常队列绑定死信交换机
当这个队列中存在死信时,RabbitMQ会自动的把这个消息重新发布到设置的DLX上,进而被路由到另一个队列,即死信队列。可以监听这个死信队列中的消息以进行相应的处理。
如代码:
@Bean("normalQueue")
public Queue normalQueue() {return QueueBuilder.durable(Constant.NORMAL_QUEUE).deadLetterExchange(Constant.DLX_EXCHANGE_NAME).deadLetterRoutingKey("dlx").build();
}
制造产生死信队列的条件
如代码:
@Bean("normalQueue")
public Queue normalQueue() {return QueueBuilder.durable(Constant.NORMAL_QUEUE).deadLetterExchange(Constant.DLX_EXCHANGE_NAME).deadLetterRoutingKey("dlx").ttl(10*1000) //消息过期时间.maxLength(10L) //队列的长度.build();
}
发送消息
如代码:
@RequestMapping("/dlx")public void dlx() {//测试过期时间, 当时间达到TTL, 消息⾃动进⼊到死信队列 rabbitTemplate.convertAndSend(Constant.NORMAL_EXCHANGE_NAME, "normal", "dlx test...");
}
项目启动后,如图:
队列Features说明:
D:durable的缩写,设置持久化
TTL:Time to Live,队列设置了TTL
Lim:队列设置了长度(x-max-length)
DLX:队列设置了死信交换机(x-dead-letter-exchange)
DLK:队列设置了死信RoutingKey(x-dead-letter-routing-key)
发送后消息进入正常的队列。
如图:
10秒后,消息过期,消息进入死信队列。
如图:
当我们发送的消息,10条往上后,溢出的也会进入死信队列。
常见面试题
1. 死信队列的概念死信(Dead Letter)是消息队列中的⼀种特殊消息,它指的是那些无法被正常消费或处理的消息。在消息队列系统中,如RabbitMQ,死信队列用于存储这些死信消息。
2. 死信的来源:
(1)消息过期:消息在队列中存活的时间超过了设定的TTL。
(2)消息被拒绝:消费者在处理消息时,可能因为消息内容错误,处理逻辑异常等原因拒绝处理该消息。如果拒绝时指定不重新入队(requeue=false),消息也会成为死信。
(3)队列满了:当队列达到最大长度,无法再容纳新的消息时,新来的消息会被处理为死信。
3. 死信队列的应用场景对于RabbitMQ来说,死信队列是⼀个非常有用的特性。它可以处理异常情况下,消息不能够被消费者正确消费而被置入死信队列中的情况,应用程序可以通过消费这个死信队列中的内容来分析当时所遇到的异常情况,进而可以改善和优化系统。
比如:用户支付订单之后,支付系统会给订单系统返回当前订单的支付状态。