在上篇中主要讲到了RabbitMQ手动响应消息,这篇主要讲到死信队列配置。
前面讲到RabbitMQ重试多次配置让他放弃消费,这样会导致消息丢失,除了放弃消费,消息丢失的情况还会有以下这几种:
- 尝试多次拒绝消费
- 消息设置了过期时间
- 消息队列满了
保证消息不丢失就需要用死信队列了,简单的讲就是指将消息放到另外一个队列,另外有一个消费者消费。
死信交换机配置类
@Configuration
class DeadExchangeConfig{
/**
* 创建死信队列
*/
@Bean
public Queue deadQueue(){
return new Queue("DEAD_QUEUE");
}
/**
* 创建死信交换机
*/
@Bean
public Exchange deadExchange(){
return new DirectExchange("DEAD_EXCHANGE");
}
/**
* 绑定死信交换机
*/
@Bean
public Binding bindingDeadExchange(Queue deadQueue, Exchange deadExchange) {
return BindingBuilder.bind(deadQueue).to(deadExchange).with("DEAD_ROUTING").noargs();
}
/**
* 创建用户业务队列
*/
@Bean
public Queue deadUserQueue(){
Map<String, Object> map = new HashMap<>();
// 绑定死信交换机
map.put("x-dead-letter-exchange", "DEAD_EXCHANGE");
// 绑定路由key
map.put("x-dead-letter-routing-key", "DEAD_ROUTING");
return new Queue("DEAD_USER_QUEUE", true, false, false, map);
}
/**
* 创建用户业务交换机
*/
@Bean
public Exchange deadUserExchange(){
return new DirectExchange("DEAD_USER_EXCHANGE");
}
/**
* 用户业务交换机
*/
@Bean
public Binding bindingDeadUserExchange(Queue deadUserQueue, Exchange deadUserExchange) {
return BindingBuilder.bind(deadUserQueue).to(deadUserExchange).with("DEAD_USER_ROUTING").noargs();
}
}
队列管理页面可以看到,业务队列绑定了DLX和DLK,就说明已经绑定死信队列
下面模拟让他报错,只重试一次,放弃消费
生产者
@RestController
@RequestMapping("/dead")
public class DeadUserCtrl {
@Autowired
private AmqpTemplate amqpTemplate;
@GetMapping("/addUser")
public String addUser(String msg){
amqpTemplate.convertAndSend("DEAD_USER_EXCHANGE", "DEAD_USER_ROUTING", "terry");
return msg;
}
}
消费者
@Component
@RabbitListener(queues = "DEAD_USER_QUEUE")
class DeadUserQueueConsumer{
@RabbitHandler
public void receive(String msg){
System.out.println(msg);
throw new RuntimeException();
}
}
配置类
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
retry:
# 开启消费者重试机制(默认就是true,false则取消重试机制)
enabled: true
# 最大重试次数
max-attempts: 1
运行,控制台报错,此时业务队列放弃消费的数据 已经放入到了死刑队列,如下图: