本篇带来TTL在rabbitmq的应用。这个TTL个人觉得还是比较重要的,比如说应用有回收站文件30天自动过期。
在学习TTL之前,先讲一下什么是死信。
什么是死信?
当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):
-
消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false
-
消息是一个过期消息,超时无人消费
-
要投递的队列消息满了,无法投递
如果这个包含死信的队列配置了dead-letter-exchange
属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机称为死信交换机(Dead Letter Exchange,检查DLX)。
死信交换机的使用场景:
-
如果队列绑定了死信交换机,死信会投递到死信交换机;
-
可以利用死信交换机收集所有消费者处理失败的消息(死信),交由人工处理,进一步提高消息队列的可靠性。
总结:
假设现在图上的都是普通的队列和交换机,平常我们队列直接都是给了消费者,但是这里simple.queue和交换机绑定,相当于消息的再投递,在这个的基础上,我让dl.direct变成死信交换机,dl.queue1变成死信队列,就我们处理ttl的 架构。
先声明普通的交换机和队列,在声明队列的时候deadLetterRoutingKey("dead").deadLetterExchange("deadExchange")
用此属性绑定死信交换机,被此属性指定的普通交换机变成了死信交换机,同时不要忘记指定
deadLetterRoutingKey,他是这个死信交换机和他绑定队列的routingkey。在ttl中指的是延迟时间。
@Bean
public Queue simpleQueue() {
return QueueBuilder.nonDurable("simpleQueue").deadLetterRoutingKey("dead")
//用deadletterExchange绑定死信交换机,只要被这个属性指定,这个普通的交换机就变成了死信
.deadLetterExchange("deadExchange").ttl(1000).build();
}
@Bean
public DirectExchange directExchange() {
return new DirectExchange("directExchange",false,false);
}
@Bean
public Binding bindingQueue() {
return BindingBuilder.bind(simpleQueue()).to(directExchange()).with("direct");
}
声明死信交换机和死信队列:
@Bean
public Queue deadQueue() {
return QueueBuilder.nonDurable("deadQueue").ttl(1000).deadLetterRoutingKey("dead2")
.deadLetterExchange("deadExchange2").build();
}
@Bean
public DirectExchange deadExchange() {
return new DirectExchange("deadExchange",false,false);
}
@Bean
public Binding bindingDeadQueue() {
return BindingBuilder.bind(deadQueue()).to(deadExchange()).with("dead");
}
@Bean
public Queue deadQueue2() {
return QueueBuilder.nonDurable("deadQueue2").ttl(1000).deadLetterRoutingKey("dead2")
.deadLetterExchange("deadExchange2").build();
}
@Bean
public DirectExchange deadExchange2() {
return new DirectExchange("deadExchange2",false,false);
}
@Bean
public Binding bindingDeadQueue2() {
return BindingBuilder.bind(deadQueue2()).to(deadExchange2()).with("dead2");
}
我这里又将死信队列和另外一个死信队列绑定了,大家可以根据需要添加。
编写生产者代码:
@GetMapping("/dead")
public void sendMessageDead(String msg){
CorrelationData correlationData = new CorrelationData();
correlationData.getFuture().addCallback(result ->{
if(result.isAck()) {
log.info("消息投递成功:" + correlationData.getId());
} else {
log.info("消息投递失败:" + result.getReason());
}
}, ex -> {
log.info("消息发送异常:" + ex.getMessage());
});
rabbitTemplate.convertAndSend("directExchange","direct",msg,correlationData);
}
这里用到了上一章讲的回调,感兴趣的小伙伴可以看看我的上篇博客。
编写消费者代码:
@Configuration
public class DeadListener {
@RabbitListener(queues= "deadQueue2")
public void process(String msg) {
System.out.println("接受到的消息是: " + msg);
}
}
最后再用postman测试自己的代码是否正确,完美解决。
不清楚的小伙伴可以留言评论哦。