作为消息队列。都可能会遇到消息丢失、重复消费、消费顺序、消息堆积这几种情况,今天就来讲解下消息丢失的场景
1、消息丢失的场景有哪些
Producter端
生产者生产完消息之后,发送消息至网络。但是由于网络原因、消息在网络上丢失了、但是生产者不知道。
RabbitmqServer端
接收到消息后由于服务器的宕机或重启等原因(消息默认是在内存中)导致消息丢失。
Comsumer端
消费者接收到消息,返回了ack。但是由于后续业务处理,出现了问题,没有完成消息的处理。
2、解决方案
Producter端
打开confirm模式后,每个被投递到这个channel的消息都会分配一个唯一ID标识,当消息写入RabbitMQ之后,RabbitMQ会回传一个ack消息给生产者,ack消息包含消息的唯一ID标识,这样生产者就能知道消息被准确收到;如果RabbitMQ没能处理这个消息,就会回传一个nack消息给生产者,这样就会调用一个我们处理nack消息的回调函数,在这个回调函数中我们可以写一些消息重发逻辑。
RabbitmqServer端
无论是生产端也好还是消费端也好,在声明queue(队列)以及exchange(交换机)的时候将它们设置为可持久化的。除此之外,在生产者发送消息时,将消息的deliveryMode设置成持久化的,这样RabbitMQ就会将消息持久化到磁盘上,即使MQ宕机了,重启后也能从磁盘上恢复消息数据。这种方案一般是配合生产者的confirm模式共同使用:只有当消息被持久化到磁盘后,MQ才会发送ack消息通知生产端。
Comsumer端
默认的消息确认机制是消费者一收到消息,就会回一个ack消息给MQ,并且MQ一收到消费端的ack消息,就会将消息从内存或磁盘中移除。我们可以在消费者订阅队列时,关闭autoAck,关闭后消费端不会一收到消息会回ack,而是在业务处理完后,需要手动调用方法发送ack消息给MQ:channel.basicAck(),MQ也会一直等待直到消费端调用basicAck,回复确认消息后,才会将消息从内存或磁盘中移除。