如何保证幂等性

一、背景:

分布式场景下,接口的开发大都需要保证幂等性。

幂等性:一个接口被调用,不管几次,产生一样的效果,一样返回结果。

接口调用过程中,很可能因为网络等原因进行重试调用,如果不能保证幂等性,那就完犊子了。

例如:用户支付的接口,用户有可能连续点击支付,总不能扣好几次钱吧。

二、场景:

1、前端重复提交:

用户快速重复点击多次,造成后端生成多个内容重复的数据。

2、接口超时重试:

对于给第三方调用的接口,为了防止网络抖动或其他原因造成请求丢失,这样的接口一般都会设计成超时重试多次。

HTTP,RPC等在超时的情况下会有重试机制。

3、消息重复消费:

MQ消息中间件,消息重复消费。

三、幂等性方案:

幂等性的保证,很明显无法通过一个方案解决所有问题,只能具体场景具体分析的。

1、业务表唯一索引:

对于数据插入的场景来说,这是最常见的方案。

核心业务字段设置为唯一索引,多次插入就会报错,从而保证幂等性。

2、状态流转控制:

状态流转也是最常见的幂等性保证手段。

如配送业务中,骑手的操作肯定会对业务流转状态进行校验。如果骑手已经提货,那就肯定不能再次提货的。

3、乐观锁版本号:

在业务表中新建一个字段version,int类型。

服务A调用服务B需要更新的时候,需要提前查询到version,然后作为参数传过去。

如果数据更新的时候将version + 1,接口如果发生重试的时候,version已经发生变更,那么也能保证幂等性。

PS:老实说,这个方案我本人没用过,有点麻烦。大部分的更新不需要保证幂等性,最终的数据也能保证一致。

4、去重:

对于前端调用的接口,有些场景无法通过前面的方案保证幂等性。

接口中可以新增一个参数,这个参数保证每次请求都是唯一的。

然后将这个参数保存,每次请求的入参校验都会查询这个参数是否存在,如果存在就返回。

参数保存的方案可以是MySQL或者Redis。

对于本身并发较低的场景,不会对MySQL服务造成压力,可以直接使用MySQL。否则,就要考虑Redis了,Redis这个key设置超时时间不用太长。

5、分布式锁:

考虑到分布式环境下,很多方案的校验如果无法保证串行的情况下,还是无法保证幂等性的。

例如,前面的状态机校验,并发环境下,可能还是会有问题,所以具体场景再进行分析。

posted @ 2022-01-25 15:21  Diamond-Shine  阅读(1505)  评论(0编辑  收藏  举报