RabbitMQ如何保证消息幂等?
RabbitMQ如何保证消息幂等?
1、生产端做消息幂等 (即不重复投递)
在生产端的话,其实消费端做好幂等,生产端就算投递多次,也无所谓了。 如果实在想在生产者做幂等的话,可以参考消费端的思路,比如通过redis的 setnx (key可以设计成 producer:具体业务:具有唯一性的某几个或者某一个业务字段 作为key) ,添加防重表等等。但是我个人觉得没必要。把消费端做好幂等就可以了。
2、消费端做消息幂等 (即不重复消费)
1 | /** |
并发高情况下可能会有IO瓶颈 (先读在写) 该方式需要在发送消息时候,指定一个业务上唯一的字段。
如 xzll:order:10001 (10001代表订单id) 然后,在消费端获取该字段,并插入到防重表中(插入代码写在哪?)
如果你声明了事务,那么插入防重这段代码位置无需关注(因为出现异常肯定会回滚),
如果没实现事务,那么最好在执行完业务逻辑后,再插入防重表,保证防重表中的数据肯定是消费成功的。实现步骤:
接收到消息后,select count(0) from 防重表 where biz_unique_id=message.getBizUniqueId();
如果大于0,那么说明以及消费过,将直接ack,告知mq删除该消息。如果=0说明没消费过。进行正常的业务逻辑。
直接写) 如果消费端业务是新增操作,我们可以为某几个或者某一个字段设置业务上的唯一键约束,
如果重复消费将会插入两条相同的记录,数据库会报错从而可以保证数据不会插入两条。
并发高下也可能会产生IO瓶颈 (先读再写) 如果消费端业务是更新操作(例如扣减库存),
可以给业务表加一个 version 字段,每次更新把 version 作为条件,更新之后 version + 1。
由于 MySQL的innoDB是行锁,当其中一个请求成功更新之后,另一个请求才能进来(注意此时该请求拿到的version还是1),
由于版本号version已经变成 2,所以更新操作不会执行,从而保证幂等。