如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?
一、有哪些可能导致重复消费
首先,我们无法避免消息被重复消费。那什么情况下会出现重复消费呢?
这里说几种可能会重复消费的情况。
1、 广播模式
一般MQ推送消息类型都有广播模式,生产者发布一条消息,订阅该Topic的消费者都会收到消息,所以一定会重复消费。
2、生产者发送重试
生产者向broker发送消息,没有收到broker的ACK,RocketMQ会进行重试
比如设置5秒发送超时就重发,生产者发了一条消息,因为网络抖动,又发了一条。但是结果第一条和第二条都发送成功了,这就导致发了2条重复的消息。
3、消费者重试
- 异常重试:由于Consumer端逻辑出现了异常,导致返回了RECONSUME_LATER状态,那么Broker就会在一段时间后尝试重试。
- 超时重试:如果Consumer端处理时间过长,或者由于某些原因线程挂起,导致迟迟没有返回消费状态,Broker就会认为Consumer消费超时,此时会发起超时重试。
4、 消费者宕机或重启
消费者消费消息后,但是还没有返回结果(即broker还没修改offset或者是否消费标识),突然宕机了或者被broker进程被kill了。
下次重启时之前那个消息会被重新消费一遍,即其实消费处理了2遍。
二、解决重复消费,保证幂等性
既然重复消费难以避免,那么我们就要保证每个消费端的处理方法即使多次执行也不影响数据和功能,即保证幂等性。
具体方法如下
1、通过redis记录消息是否消费过
让生产者发布消息提供一个businessId字段,用来保证唯一性。每次处理的时候,往redis里存一下记录,下次消费的时候根据key判断一下消息是否消费过
2、通过数据库查询逻辑判断是否能插入或更新
比如消费者处理方法是往表里插入一条数据或者更新一条数据,可以先判断一下数据是否存在或者是否能更新。
小声说:不过我发现我们公司很多代码似乎是没有做这方面处理,这其实是开发不负责任的表现,当然也可能是没有这方面意识
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏