35 引入幂等性机制,保证数据不会重复

Posted 鮀城小帅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了35 引入幂等性机制,保证数据不会重复相关的知识,希望对你有一定的参考价值。

1. 什么是幂等性机制

所谓幂等性机制,就是用来避免对同一个请求或者同一条消息进行重复处理的机制。幂等的意思是,你有一个接口,如果别人对一次请求重试了多次,来调用你的接口,你必须保证自己系统的数据是正常的,不能多出来一些重复的数据,这就是幂等性的意思。

因此要避免MQ中的消息进行重复处理,可以采用幂等性机制

2.发送消息到MQ的时候如何保证幂等性?

在前面的场景中,订单系统的接口可能会被重复调用导致发送重复的消息到MQ去,也可能自己有重试机制导致发送重复的消息到MQ。

要让订单系统别发送重复的消息到MQ去,共有以下两种方案:

第一个方案就是业务判断法,也就是说你的订单系统必须要知道自己到底是否发送过消息到MQ去,消息到底是否已经在MQ里了。

场景说明:

当支付系统重试调用订单系统接口时,由订单系统发送一个请求到MQ去,查询一下当前MQ是否存在针对这个订单的支付消息?

如果MQ返回 id=1100的订单的支付成功消息,就说明已经写进去了,此时订单系统不要再次发送这条消息到MQ去了。

 在业务判断法中,你的消息是存在MQ里的,有没有发送过这个消息也只有MQ知道。

所以当你的订单系统的接口被重试调用的时候,在接口上发送请求到MQ去查询 id=1100 这个订单的支付成功消息,就能确定是否已经发送过该消息到MQ了,如果有,就不要在重复发消息了。

3.基于Redis缓存的幂等性机制

这是第二种方法,也就是状态判断法。

该方法的核心是,引入Redis缓存来存储你是否发过消息的状态,

场景说明:

如果你发送了一条消息到MQ,那么就在Redis缓存中写入一条数据,标识你已经发过这条消息了。

那么当你的订单接口被重复调用的时候,就使用订单id去redis里面去查找是否已经写入对应的数据,如果已经存在,那就说明已经发送过该消息给MQ了,就不要再发送了。

4. 以上两种方案的弊端以及是否必要

以上的两种方法都是发送消息实现 幂等性的方案。

基于Redis实现的状态判断法并不能绝对保证幂等性,这是因为基于Redis的实现是必须由生产者去写入数据到Redis来进行标识MQ消息的已经写入的。

这就存在一种情况,此时生产者将消息成功写入MQ,在收到commit状态时,正好要将订单id写入Redis的时候,生产者突然宕机了,那么就没能写入Redis中。在订单系统重启后,订单接口被重调,向Redis中是查询不到已经发送过当前订单消息的标识数据的,就会再次发送消息,从而导致重复发送消息。

基于查询MQ的业务判断法,因为每次都需要去查询请求MQ,这就会造成接口的性能问题,并不是很推荐这种方式。(MQ是支持查询这个MQ是否存在的)

5.在业务环节去保证消息处理的幂等性

以优惠券系统为例,这里可以使用业务判断法。优惠券系统每次拿到一条消息都会给用户派发一张优惠券,实际上就是在数据库里给用户插入一条优惠券记录。

如果优惠券系统收到MQ那里拿到一个订单的两条重复的支付成功消息。就可以直接去查询优惠券数据库中的数据。比如id=1100的优惠券记录是否存在,不存在则可以派发写入优惠券数据到DB中;如果已经存在,就不要派发优惠券了。

这种在业务逻辑中的业务判断法,明显能更加简单且高效的避免消息的重复消费。

6. 关于幂等性避免MQ消息重复消费的总结

向MQ重复发送多个一样的消息,对于MQ来说是可以让多个相同消息同时存在的,这不会对系统造成影响。但要注意的是,在业务层面从MQ里获取消息进行处理的时候,必须要保证消息不会重复处理。

这就要保证消息的幂等性。优先选择的方案是业务判断法,它可以直接在业务层面根据数据库中存储的数据来判断这条消息是否已经处理过了,如果处理过了,就别再处理了。

以上是关于35 引入幂等性机制,保证数据不会重复的主要内容,如果未能解决你的问题,请参考以下文章

高并发下保证接口的幂等性的几种方式

高并发下保证接口的幂等性的几种方式

高并发下保证接口的幂等性的几种方式

MQ中的坑及高并发下保证接口的幂等性

MQ中的坑及高并发下保证接口的幂等性

RabbitMQ消息幂等性问题