目录
消息队列 RabbitMQ[一] RabbitMQ的下载与安装
消息队列 RabbitMQ[二] RabbitMQ可视化管控台创建用户并为用户分配虚拟机
消息队列 RabbitMQ[三] RabbitMQ的HelloWorld工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[四] RabbitMQ的Publish/Subscribe(发布/订阅)工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[五] RabbitMQ的Routing工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[六] RabbitMQ的Topics工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[七] RabbitMQ保证消息的可靠性传递(Confirm Return Ack)
消息队列 RabbitMQ[八] SpringBoot Consumer 限流机制
消息队列 RabbitMQ[九] SpringBoot 设置消息过期时间TTL
消息队列 RabbitMQ[十] SpringBoot 死信队列与延迟队列实现思路
消息流动图:
如上图可知消息从生产者到消费者要经历三个阶段
- 生产者(Producer)发送到交换机(Exchange)
- 交换机发送到队列(Queue)
- 消费者从队列中取得的数据
那RabbitMQ要怎么保证每一阶段数据都是成功送到了呢??它提供了三种机制来保证消息的可靠性,三种机制分别对应三个阶段
一、Confirm机制
confirm机制能够用来保证消息从生产者到交换机的可靠性,它是一种确认模式,当你开启的时候,RabbitMQ会在生产者发送消息到交换机之后执行一个我们自定义的回调函数,不管生产者发送成功还是发送失败,当生产者发送失败时,我们可以在回调函数中重新发送失败的消息,这样就确保了消息能够从生产者到交换机。
1. 开启Confirm模式
spring:
rabbitmq:
...
publisher-confirm-type: correlated #开启confirm模式
2. 编写测试代码
@Test
public void testTopicsSend(){
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if (b){
System.out.println("发送成功");
}else {
System.out.println("发送失败");
// 这里可以写发送失败的处理逻辑,比如重新发送
}
}
});
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "log.error", "hello rabbitmq");
rabbitTemplate.convertAndSend("xxx", "log.info", "hello rabbitmq");
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "log.warning", "hello rabbitmq");
}
由于第二个交换机名称xxx是瞎写的所以有一个会发送失败
二、Return机制
Return机制能够用来保证消息从交换机到队列的可靠性,当你开启的时候,也会执行一个自定义的回调函数,但只有交换机到队列发送失败时才会执行
1. 开启Return模式
spring:
rabbitmq:
...
publisher-returns: true #开启return机制
2. 编写测试代码
@Test
public void testTopicsSend(){
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
// message 就是发送失败的消息
System.out.println(new String(message.getBody()));
}
});
// 随便写一个routingkey让它发送失败
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "log.infoxx.xxx.xx", "hello rabbitmq");
}
三、Ack机制
确认机制(Ack)有两种
- 自动确认:当消费者收到消息之后,立即确认消息,消息就会从MQ中移除
- 手动确认:等待消费者手动确认之后,消息才会从MQ中移除
确认机制可以解决什么问题呢?
当消费者收到消息之后,如果是自动确认,这时消息已经从MQ中消失了,然而消费者在处理消息时发生了错误导致消息丢失了,这时消息就真的丢失了。当我们使用手动确认时,可以在消息处理之后在确认,这样就算处理错误导致消息丢失也可以再次总MQ中获取到消息
1. 开启手动确认
spring:
rabbitmq:
...
listener: # 消费者监听设置手动确认
direct:
acknowledge-mode: manual
simple:
acknowledge-mode: manual
2. 编写消费者代码
@RabbitListener(queues = "direct_queue1")
public void listenQueueFanoutQ1(Message message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
try {
// 业务逻辑处理成功,手动确认
/*
* tag: 消息标记
* false: 不是多消息
*/
channel.basicAck(tag, false);
} catch (Exception e) {
// 处理过程中,发生了异常,不进行确认
/*
* tag: 消息标记
* false: 不是多消息
* true: 将消息重新返回到队列
*/
channel.basicNack(tag, false, true);
// 从MQ中再次获取消息
}
System.out.println(new String(message.getBody()));
}