什么是消息幂等
当出现消费者对某条消息重复消费的情况时,重复消费的结果与消费一次的结果是相同的,并且多次消费并未对业务系统产生任何负面影响,那么这整个过程就可实现消息幂等。
假设报备服务和积分服务之间是用mq消息进行交互,经纪人报备后,报备服务发出积分加5的mq消息,积分服务接到mq之后就会给经纪人帐号加5积分。 如果积分服务多次接收到同一个消息,就会执行多次积分加5的动作,导致经纪人的积分多加了。
适用场景
在互联网应用中,尤其在网络不稳定的情况下,消息队列的消息有可能会出现重复。如果消息重复会影响您的业务处理,请对消息做幂等处理。
消息重复的场景如下:
-
发送时消息重复
当一条消息已被成功发送到服务端并完成持久化,此时出现了网络闪断或者客户端宕机,导致服务端对客户端应答失败。 如果此时生产者意识到消息发送失败并尝试再次发送消息,消费者后续会收到两条内容相同并且Message ID也相同的消息。 -
投递时消息重复
消息消费的场景下,消息已投递到消费者并完成业务处理,当客户端给服务端反馈应答的时候网络闪断。为了保证消息至少被消费一次,消息队列RocketMQ版的服务端将在网络恢复后再次尝试投递之前已被处理过的消息,消费者后续会收到两条内容相同并且Message ID也相同的消息。 -
负载均衡时消息重复(包括但不限于网络抖动、Broker重启以及消费者应用重启)
当消息队列RocketMQ版的Broker或客户端重启、扩容或缩容时,会触发Rebalance,此时消费者可能会收到重复消息。
Fdd的mq平台解决方案
1、接收到mq消息后,根据消息id查询是否已经消费过该消息。如果消费过该消息,转步骤5;如果没有消费过,转步骤2
2、保存mq消费记录,保存成功,转步骤3,保存失败,转步骤5(多消费者的情况下,保证mq消息也只被消费一次!!!,这里以messageId+applicationId作为唯一索引,插入失败表示已经有人处理过了,就不在处理)
3、执行正常的mq消费逻辑,消费成功,转步骤5,消费失败,转步骤4
4、消费失败,删除mq消费记录,nack消息并requeue,结束(确保mq消息下次到达时,可以被消费)
5、消费成功,ack确认mq消息,结束
注意的点:在插入消费记录之前开启事务,在成功消费mq消息之后,提交事务,消费失败则回滚事务。这样可以避免出现mq消费失败之后,清理消费记录失败,导致消息无法被消费的问题。
如果不用事务,比如用redis存储,就需要用分布式锁,处理并发消费的问题;