之前看很多网上大佬的防丢失的文章,文章中理论知识偏多,所以自己想着实践一下,实践过程中也踩了一些坑,因此写出了这篇文章。如果文章有误人子弟的地方,望在评论区指出。
导致消息出现丢失的原因
-
发送时失败,指发送端发送完消息准备到达消息队列的过程中,因网络波动、消息队列服务宕机等,消息队列服务无法接收消息,所以导致了丢失。
-
到达时宕机,消息队列服务接收到消息之后,如果没有开启持久化,消息会存储在内存中(当然内存吃紧的话,也会转入磁盘,缓解内存),如果这个时候服务挂了,那么内存中的消息就会丢失。
-
发送到消费端失败,消费端接收到了消息的时候,消费端服务挂了,而rabbitmq默认自动ack,也就是说rabbitmq发送到消费端,一旦认定了消费端接收了,无论有无消费成功,rabbitmq都认为是发送成功。
下面我们以这三种情况进行实践。
环境
jdk1.8 Spring boot 2.3.7.RELEASE Spring-boot-starter-amqp 2.3.7.RELEASE Rabbitmq 3.7.7
准备工作
我事先准备了好了交换机以及队列
-
交换机:message.log.test.exchange和message.log.test2.exchange
-
队列:message.loss.test.queue
其中message.loss.test.queue和message.log.test.exchange是绑定关系,而 message.log.test2.exchange没有绑定队列
1.发送时失败
发送时失败,rabbitmq有两种情况是属于发送时失败。
-
消息未到rabbitmq的交换机(exchange)
-
消息到达了rabbitmq的交换机(exchange),但是没有到达队列(queue)
第一种的解决方式是使用confirm机制。第二种解决方式则是使用return机制。
使用confirm机制
模拟场景
confirm机制是当发送端的消息没有到达rabbitmq的交换机(exchange)时,会触发confirm方法,告诉发送端该消息没有到达rabbitmq,需要做业务处理。 这里我们发送消息到rabbitmq不存在的交换机上,就可以模拟上述场景。
实现RabbitTemplate.ConfirmCallback接口
/**
* 当消息没有到达Rabbitmq的交换机时触发该方法(当然到达了也会触发,)
*/
@Component
publi