【RabbitMQ】消息丢失原因及解决方案

前言:

        (1)如今项目都会引入消息队列组件,无论是Kafka、RocketMQ还是RabbitMQ,特点和使用上可能有所区别,但主要目的都是一致的:应用解耦异步提速流量削峰

        (2)应用解耦:现在有很多项目的模块都是区分开的,比如订单模块和库存模块,当用户下单成功后,订单模块肯定要调用库存模块的接口,如果此时库存模块出现异常,那么订单模块也会受牵连出现异常,而消息队列的引入就相当于在这两个模块间架了一座桥,让两个模块的耦合度降低。

        (3)异步提速还是订单模块与库存模块的例子,订单模块扮演生产者,库存模块扮演消费者。一般生产者在投递完消息后就可以直接响应用户, 无需等待消费者消费消息。如果传统的同步方式,每一个接口的调用都要耗费相应时间,加一块耗时还是比较高的

        (4)流量削峰在请求数量超过系统所能承载的数量时,可将请求先放在MQ中,系统再从MQ中拉取并处理请求,填谷值在高峰期过后的一段时间内,由于消息积压在MQ中,消费消息的速度还是会维持在系统阈值左右,直到消费完积压的消息。

什么是消息丢失?

        通俗点讲就是消费从生产者生成到消费者消费这个过程中,消息没有真正的被消费者处理。它可能在传递过程中丢失了,消费者根本没有接收到;或者是消费者在处理消息时出现异常了,消息没有被真正的处理完毕,这都属于消息丢失的范畴。

消息丢失有几种情况,如何解决?

        (1)生产端丢失消息

                消息在被生产者生产后,发送到MQ的这个过程中,由于网络等原因导致消息没有发送到MQ,或者MQ没有收到消息。

                解决方案

                RabbitMQ有confirm模式,生产者实例可以在发送消息前可以开启confirm模式,打开confirm模式后,每个被投递到这个channel的消息都会分配一个唯一ID标识,当消息写入RabbitMQ之后,RabbitMQ会回传一个ack消息给生产者,ack消息包含消息的唯一ID标识,这样生产者就能知道消息被准确收到;如果RabbitMQ没能处理这个消息,就会回传一个nack消息给生产者,这样就会调用一个我们处理nack消息的回调函数,在这个回调函数中我们可以写一些消息重发逻辑。

        (2)MQ丢失消息

                消息一般都是存储在内存中的,当消息到达RabbitMQ后,RabbitMQ因为一些原因宕机了,内存中的数据肯定不复存在,导致消息丢失。

                解决方案

                无论是生产端也好还是消费端也好,在声明queue(队列)以及exchange(交换机)的时候将它们设置为可持久化的。除此之外,在生产者发送消息时,将消息的deliveryMode设置成持久化的,这样RabbitMQ就会将消息持久化到磁盘上,即使MQ宕机了,重启后也能从磁盘上恢复消息数据。这种方案一般是配合生产者的confirm模式共同使用:只有当消息被持久化到磁盘后,MQ才会发送ack消息通知生产端。

        (3)消费端丢失消息

                消费端在处理消息的过程中出现异常,消息没有得到正常、恰当的处理,导致消息丢失。

                解决方案:

                默认的消息确认机制是消费者一收到消息,就会回一个ack消息给MQ,并且MQ一收到消费端的ack消息,就会将消息从内存或磁盘中移除。我们可以在消费者订阅队列时,关闭autoAck,关闭后消费端不会一收到消息会回ack,而是在业务处理完后,需要手动调用方法发送ack消息给MQ:channel.basicAck(),MQ也会一直等待直到消费端调用basicAck,回复确认消息后,才会将消息从内存或磁盘中移除。

                以上是本人在学习过程中学习到的一些对于消息丢失问题的解决方案,有不对或不完善的地方,还请在评论区不吝赐教,感谢垂阅。

你可能感兴趣的:(rabbitmq,分布式)