幂等性如何保证

男娘i 2023-01-12 15:56 262阅读 0赞

1 幂等性" class="reference-link">因为申请较晚,本公众号没留言,想交流的欢迎添加私人微信,一起相互吹捧,共同进步。c58d1b29dad33f508ff4934d8c13f606.png1 幂等性

1.1 定义

幂等概念来自数学,表示对数据源做N次变换和1次变换的结果是相同的。在工程中幂等性用来表示用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。

  1. 幂等包括第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。
  2. 幂等关注的是以后的多次请求是否对资源产生的副作用,而不关注结果。
  3. 网络超时等问题,不是幂等的讨论范围。
  4. 幂等性是系统服务对外一种承诺,而不是实现,承诺只要调用接口成功,外部多次调用对系统的影响是一致的。声明为幂等的服务会认为外部调用失败是常态,并且失败之后必然会有重试。

1.2 场景

业务开发时,可能会遇到由于网络震荡导致请求无法收到导致触发了重试机制,或者前端抖动导致表单重复提交这样的情况。比如在交易系统中,用户提交购物请求已经被服务器端正确处理,但服务器端的返回结果由于网络等原因被掉丢了,导致客户端无法得知处理结果。如果是在网页上,一些不恰当的设计可能会使用户认为上一次操作失败了,然后刷新页面,这就导致了扣款被调用两次,账户也被多扣了一次钱。此时就需要引入幂等性接口了。

我们以MySQL为例,只有第三种场景需要开发人员使用其他策略保证幂等性:

  1. SELECT col1 FROM tab1 WHER col2=2;
  2. -- 无论执行多少次都不会改变状态,是天然的幂等。
  3. UPDATE tab1 SET col1=1 WHERE col2=2;
  4. -- 无论执行成功多少次状态都是一致的,因此也是幂等操作。
  5. UPDATE tab1 SET col1=col1+1 WHERE col2=2;
  6. -- 每次执行的结果都会发生变化,这种不是幂等的。

这里说下重复提交跟幂等性的区别:

  1. 重复提交是在第一次请求已经成功的情况下,人为的进行多次操作,导致不满足幂等要求的服务多次改变状态。
  2. 幂等更多使用的情况是第一次请求不知道结果(比如超时)或者失败的异常情况下,发起多次请求,目的是多次确认第一次请求成功,却不会因多次请求而出现多次的状态变化。

1.3 幂等性思考

引入幂等性后会使得服务端逻辑更加复杂,满足幂等性的服务需要在逻辑中至少包含两点:

  1. 首先去查询上一次的执行状态,如果没有则认为是第一次请求。
  2. 在服务改变状态的业务逻辑前,保证防重复提交的逻辑。

幂等性可以简化客户端逻辑处理,但却增加了服务提供者的逻辑和成本,所以是否要用,需根据具体场景具体分析,因此除了业务上的特殊要求外,尽量不提供幂等的接口。

  1. 增加了额外控制幂等的业务逻辑,复杂化了业务功能。
  2. 把并行执行的功能改为串行执行,降低了执行效率。

2 幂等性解决

2.1 前端设置

在用户点击完提交按钮后,我们可以把按钮设置为不可用或者隐藏状态。

66e0ef96e2fcba6cd39c1df2a99cdea3.gif
前端限制比较简单,但有个致命错误,如果碰到懂行的用户通过模拟网页请求来重复提交请求,绕过了前端限制。

2.2 唯一索引

防止订单多次插入的最简单直接方法就是创建唯一索引,然后插入的时候可能语句有细微的不同。但目的都是保证相同记录在数据库中只存在一条。

  1. 方法一:给数据库添加唯一索引,然后如果执行时捕捉到了DuplicateKeyException会明白是重复插入导致的,继续往下执行业务即可。
  2. 方法二:利用MySQL自带的关键字ON DUPLICATE KEY UPDATE 实现不存在则插入,存在则更新的操作,该关键字不会删除原有的记录。
  3. 方法三:replace into 主要作用类似 INSERT 插入操作,replace into底层是先删除后插入数据,会破坏索引、重新维护索引。需注意必须要有主键或唯一索引才能有效,否则replace into就只新增了。

2.3 去重表

去重表的机制是根据mysql唯一索引的特性来的,大致流程:

  1. 客户端先请求服务端,服务端先将这次的请求信息存入一张mysql的去重表中,这张表要根据这次请求的其中某个特殊字段建立唯一索引,或者主键索引。
  2. 判断是否插入成功,如果插入成功,则继续做后续业务请求。如果插入失败,则代表已经执行过当前请求。

2fdb2c9d6b2e4fee5fa84ba6db0f9170.png

2.4 悲观锁

8689666486b138996bde62da40019a28.png
方式一:简单的利用Java自带的syn 或 lock 锁实现幂等性。核心点在于将重要的执行部分将并行切换为串行。缺点是这个锁在分布式场景是不能用的,因为都跨JVM了!此时需要引入分布式锁了。
365caae9be210905473187d1e2f46888.png
依靠MySQL自带的 for update操作数据库,来实现串行化。这里的重点在于 for update,简单说明下:

  1. 当线程A执行for update,数据会对当前记录加锁,其他线程执行到此行代码的时候,会等待线程A释放锁之后,才可以获取锁,继续后续操作。
  2. 事物提交时,for update获取的锁会自动释放。

该模式的缺点是,如果业务处理比较耗时,并发情况下,后面线程会长期处于等待状态,占用了很多线程,让这些线程处于无效等待状态,而web服务中的线程数量一般有限的,如果大量线程由于获取for update锁处于等待状态,不利于系统并发操作。

2.5 乐观锁

对每行数据添加个version字段,这里其实跟秒杀设计中的思路类似,利用MySQL自带的当前读更新操作。在更新数据时候先查询获得对应版本号,然后尝试update操作,根据返回值是否为0来确保是否是重复提交。

  1. select id,name,account,version from user where id = 1412; // 假设获得的 version = 10
  2. update user set account = account + 10,version = version + 1
  3. where id = 1412 and version = 10;

59cfd14f94898d9f3121ae353f3e9316.png

2.6 分布式锁

使用Redis中的setnx操作,将幂等性的保证屏障设置在分布式锁中。如果setnx成功了说明这是第一次进行数据插入,继续执行SQL语句即可。如果setnx失败了,那说明已经执行过了。

c12f9d4d8060cfabd8dba836ba2f7b94.png

2.7 token 方案

这种方式分成两个阶段:申请token阶段和支付阶段。

  1. 第一阶段:在进入到提交订单页面之前,需要订单系统根据用户信息向支付系统发起一次申请token的请求,支付系统将token保存到Redis缓存中,为第二阶段支付使用。
  2. 第二阶段:订单系统拿着申请到的token发起支付请求,支付系统会检查Redis中是否存在该token,如果存在,表示第一次发起支付请求,删除缓存中token后开始支付逻辑处理;如果缓存中不存在,表示非法请求。

实际上这里的token可以认为是一个信物,支付系统根据token确认插入的唯一性。token模式不足之处在于,需要系统间交互两次,流程较上述方法复杂。

token token

参考

  1. MySQL操作:https://blog.csdn.net/qq\_18975791/article/details/107285455
  2. 苏三说幂等:https://mp.weixin.qq.com/s/v4CamZlqHP8gEmubzPme4g
  3. 幂等性实现:https://blog.csdn.net/wanglei303707/article/details/88298211

发表评论

表情:
评论列表 (有 0 条评论,262人围观)

还没有评论,来说两句吧...

相关阅读

    相关 如何保证接口

    为什么需要保证接口幂等性 因为在很多业务场景中,为了保证业务正确性,往往会出现重复请求或着重复消息的情况。特别是在分布式系统中,由于网络不稳定或者负载均衡等原因,可能会出

    相关 接口的如何保证

    1. 接口调用存在的问题 现如今我们的系统大多拆分为分布式SOA,或者微服务,一套系统中包含了多个子系统服务,而一个子系统服务往往会去调用另一个服务,而服务调用服务无非就

    相关 如何保证

    因为申请较晚,本公众号没留言,想交流的欢迎添加私人微信,一起相互吹捧,共同进步。![c58d1b29dad33f508ff4934d8c13f606.png][]1 幂等性

    相关 RabbitMQ如何保证

    幂等性是分布式系统设计中的一个重要概念,是在做系统或者接口设计时要着重考虑的问题,尤其像支付宝、银行、互联网金融等涉及钱的系统,既要高效,数据也要准确,绝对不能出现多扣款,多打

    相关 保证接口

    什么是幂等 幂等性:其实就是数据一致性和事务完整性 数学上的定义:f(f(x))=f(x)。x被函数f作用一次和作用无限次的结果是一样的。幂等性应用在软件系统中,可以

    相关 如何保证接口的

    什么是幂等性 HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的

    相关 如何保证接口的

    当通过调用创建实例接口在负载均衡中创建云服务器时,如果遇到了请求超时或服务器内部错误时,客户端可能会尝试重发请求,这时客户端可以通过提供可选参数 ClientToken ...