RabbitMQ保证消息可靠性
首先我们回顾一下RabbitMQ的消息发送过程:

我们基于springboot来进行简单实现
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
创建RabbitMQ的配置类
@Configuration
public class RabbitMQConfig {
//交换机名称
public static final String EXCHANGE = "boot-exchange";
//队列名称
public static final String QUEUE = "boot-queue";
//路由规则
public static final String ROUTING_KEY = "*.black.*";
@Bean
public Exchange bootExchange(){
return ExchangeBuilder.topicExchange(EXCHANGE).build();
}
@Bean
public Queue bootQueue(){
//创建的队列持久化
return QueueBuilder.durable(QUEUE).build();
}
@Bean
public Binding bootBinding(Exchange bootExchange, Queue bootQueue){
//绑定交换机和队列
return BindingBuilder.bind(bootQueue).to(bootExchange).with(ROUTING_KEY).noargs();
}
}
配置文件
spring:
rabbitmq:
host: xxx.xxx.xxx.xxx #根据情况自行填写服务ip
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
acknowledge-mode: manual #开启手动ack
prefetch: 1
publisher-confirm-type: correlated # 新版本
#publisher-confirms: true # 老版本
publisher-returns: true # 开启Return机制
template:
mandatory: true
当一个消息无法被路由到任何队列时:
mandatory: false 消息会被 RabbitMQ 直接丢弃
mandatory: true 会返回给生产者一个 Basic.Return 响应,生产者可以在 ReturnCallback 回调函数中对这种情况进行处理
通过confirm模式保证消息一定送达到Exchange
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if(ack){
System.out.println("消息已经送达到交换机!");
}else{
System.out.println("消息没有送达Exchange,需要补偿操作!!!");
}
});
保证消息可以路由到Queue
//消息路由失败时通过回调函数作对应处理
rabbitTemplate.setReturnsCallback(returned -> {
String msg1 = new String(returned.getMessage().getBody());
System.out.println("消息:" + msg1 + " 路由到队列失败!");
});
保证Queue可以持久化消息
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE, routingKey, msg, message -> {
// 设置消息的持久化!
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return message;
});
手动ACK确认消息
这部分在消费端处理
@Component
public class ConsumeListener {
@RabbitListener(queues = RabbitMQConfig.QUEUE)
public void consume(String msg, Channel channel, Message message) throws IOException {
System.out.println("队列的消息为:" + msg);
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
}
完整生产者代码如下:
@SpringBootTest
public class publish {
@Test
public void publishWithConfirms() throws IOException {
String routingKey = "big.black.dog";
String msg = "Hello World";
//通过confirm模式确保消息发送到交换机
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if(ack){
System.out.println("消息已经送达到交换机!");
}else{
System.out.println("消息没有送达Exchange,需要补偿操作!!!");
}
});
//消息路由失败时通过回调函数作对应处理
rabbitTemplate.setReturnsCallback(returned -> {
String msg1 = new String(returned.getMessage().getBody());
System.out.println("消息:" + msg1 + " 路由到队列失败!");
});
//设置消息持久化
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE, routingKey, msg, message -> {
// 设置消息的持久化!
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return message;
});
System.out.println("消息发送成功");
System.in.read();
}
}