聊聊MQ,如何避免消息丢失?如何避免重复消费?

2022-04-27  本文已影响0人  Java码农

前言

我在工作中,使用到消息中间件MQ的业务还是挺多的,我从事在一家交通行业的公司,业务中经常会涉及处理一些违法数据的场景,项目中经常会使用到RabbitMQ,今天想跟大家聊聊怎样避免消息丢失和重复消费是问题。

在我们发生消息的时候,如果MQ服务器突然宕机了会出现什么情况?是不是我们发过去的消息全部没有了吗?

是的,一般MQ中间件为了提高系统的吞吐量会把消息保存在内存中,如果不作其他处理,MQ服务器一旦宕机,消息将全部丢失。这个是业务不允许的,造成很大的影响。

在遇到这种问题的时候,一般有以下几种处理方式。

如何避免消息丢失

持久化

RabbitMQ中发消息的时候会有个durable参数可以设置,设置为true,就会持久化。

这样的话MQ服务器即使宕机,重启后磁盘文件中有消息的存储,这样就不会丢失了吧。是的这样就一定概率的保障了消息不丢失。

但还会有个场景,就是消息刚刚保存到MQ内存中,但还没有来得及更新到磁盘文件中,突然宕机了。这个场景在持续的大量消息投递的过程中,会很常见。

那怎么办?我们如何作才能保障一定会持久化到磁盘上面呢?

confirm机制

RabbitMQ利用confirm机制来通知我们是否持久化成功?

confirm机制的原理:

(1)消息生产者把消息发送给MQ,如果接收成功,MQ会返回一个ack消息给生产者;

(2)如果消息接收不成功,MQ会返回一个nack消息给生产者;

这样是不是就可以保障100%消息不丢失了呢?

如果我们生产者每发一条消息,都要MQ持久化到磁盘中,然后再发起ack或nack的回调。这样的话是不是我们MQ的吞吐量很不高,因为每次都要把消息持久化到磁盘中。写入磁盘这个动作是很慢的。这个在高并发场景下是不能够接受的,吞吐量太低了。

所以MQ持久化磁盘真实的实现,是通过异步调用处理的,他是有一定的机制,如:等到有几千条消息的时候,会一次性的刷盘到磁盘上面。而不是每来一条消息,就刷盘一次。

所以comfirm机制其实是一个异步监听的机制,是为了保证系统的高吞吐量,这样就导致了还是不能够100%保障消息不丢失,因为即使加上了confirm机制,消息在MQ内存中还没有刷盘到磁盘就宕机了,还是没法处理。

数据库事务机制

生产者在投递消息之前,可以在本地数据库建一张消息表,先把消息持久化到Redis或DB中,这样就可以利用本地数据库的事务机制。事务提交成功后,将消息表中的消息转移到消息队列中。

confirm机制监听消息是否发送成功?如ack成功消息,删除DB中此消息。

如果nack不成功的消息,这个可以根据自身的业务选择是否重发此消息。也可以删除此消息,由自己的业务决定。

如何避免消息重复消费

幂等性也就是相同条件下对一个业务的操作,不管操作多少次,结果都是一样。

重复消费的问题?

导致重复消费的原因可能出现在生产者,也可能出现在 MQ 或 消费者。

这里说的重复消费问题是指同一个数据被执行了两次,不单单指 MQ 中一条消息被消费了两次,也可能是 MQ 中存在两条一模一样的消费。

如何保证幂等性?

消费者怎么解决重复消费问题呢?这里提供两种方法:

上一篇 下一篇

猜你喜欢

热点阅读