MQ保证消息幂等
如何保证消息只被消费一次
- 目录
- 消息丢失出现在哪些情况?
- 如何解决消息重复消费
- 误区
目录
如何保证消息只被消费一次?
首先需要保证消息不被丢失,消息丢失的原因?
消息丢失出现在哪些情况?
1.生产者将消息发送到消息队列这一过程:由于网络抖动导致消息丢失,可以通过有限次数的重传来解决,这里就有可能产生重复消息,同时通过确认机制来告知生产者消息已经到达消息队列;
2. 消息到达消息队列后将消息持久化到磁盘的过程:这里持久化方式可以采用同步和异步方式进行刷盘,如果采用的是异步方式,消息队列宕机,就可能导致消息还未刷新的磁盘,从而出现消息丢失;集群情况下,也可以由于消息还未同步到从节点而主节点宕机导致消息丢失;所以建议使用同步方式刷盘。
3.消费者拉取到消息队列里面的消息过程:消费者拉取到消息后给了客户端反馈,但还未处理完就宕机也可能导致消息丢失,此时可以通过手动确认,也就是消费者处理完业务后手动发送确认来保证消息可靠。
如何解决消息重复消费
从上面分析可以看出,为了保证消息一定能被消费者消费,采用了重传和确认来实现,所以就会出现消息重复消费的现象。如何解决呢?通过一个记录表,流程如下:
其中的记录表可以使用redis来实现,但同时就会存在redis的一些问题。
误区
一开始我认为是通过rocketmq、rabbitmq中内置的一个messageId来实现,实际上不完全。
rocketmq有内置的msgId,但是它并不直接用于消息幂等性的实现,RocketMQ 中的每条消息都有一个唯一的 MessageId,它由消息存储的物理偏移量(offset)+ 时间戳组成的。
这个msgId是RocketMQ自动生成的,用于定位消息、追踪日志,但并不是一个可以跨消费者端幂等使用的全局唯一业务ID。msgId 是 RocketMQ 自动生成的,不是业务自定义的,它可能会在消息重试或重新发送时发生变化。 rocketmq可以在生产者发送消息时附带一个业务ID。
而rabbitmq中消息可以有message-id字段,需要生产者主动设置message-id。
所以如果要保证消息的幂等性,可以通过记录表(去重表)来判断当前的业务id是否存在,然后在消费端来实现幂等。
参考资料:
[1]: https://www.bilibili.com/video/BV1zVp1e3Ejn/?spm_id_from=333.337.search-card.all.click&vd_source=de349d448ecee694c04e5b2e7b5ed936
[2]: GPT