• 如何保证幂等性 Diamond


    一、背景:

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

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

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

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

    二、场景:

    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、分布式锁:

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

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

  • 相关阅读:
    Java实现 LeetCode 400 第N个数字
    Java实现 LeetCode 400 第N个数字
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 398 随机数索引
    Java实现 LeetCode 398 随机数索引
    Java实现 LeetCode 398 随机数索引
    linux中的cd ..和cd -命令有什么区别?
    GCC使用
  • 原文地址:https://www.cnblogs.com/huigelaile/p/15843021.html
Copyright © 2020-2023  润新知