美文网首页
如何保证接口的幂等性?

如何保证接口的幂等性?

作者: 靓仔聊编程 | 来源:发表于2021-08-22 10:43 被阅读0次

今天我们来聊聊关于接口的幂等性问题。

什么是幂等性

所谓幂等,就是任意多次执行所产生的影响均与一次执行的影响相同。

在 restful 规范中,常见的请求方式和接口幂等性关系如下:

请求方式 操作 是否幂等
GET 查询数据
POST 新增数据
PUT 更新数据 直接更新为某个值,满足幂等,如:set a = 1;累加操作的更新,不满足,如:set a = a+1
DELETE 删除数据 根据唯一条件删除,满足幂等;否则,不满足,幂等,比如:根据某一条件删除一批数据后,又新增了一条满足该条件的数据,又执行了一次删除,那么就会删除掉新增的这条数据

为什么会产生接口幂等性问题

在计算机应用中,可能遇到网络抖动,临时故障,或者服务调用失败,尤其是分布式系统中,接口调用失败更为常见。为了保证服务的完整性,我们可能会发起接口的重试调用,如果接口不处理幂等,可能对系统造成很大的影响,因此接口的幂等设计尤其更为重要。

对于业务中需要考虑幂等性的地方一般都是接口的重复请求,重复请求是指同一个请求因为某些原因被多次提交。导致这种情况的发生有以下几种常见的场景:

  1. 前端重复提交:用户在提交表单的时候,可能会因网络波动没有及时做出提交成功响应,致使用户认为没有成功提交,然后一直点提交按钮,这时就会发生重复提交表单请求。

  2. 接口超时重试:第三方调用接口时候,为了超时等异常情况造成的请求失败,都会添加重试机制,导致一个请求提交多次。

  3. 消息重复消费:当使用 MQ 消息中间件时候,如果发生消息中间件出现错误未及时提交消费信息,导致发生重复消费。

幂等性解决方案

那我们应该能怎样保证接口的幂等性呢?

可以思考一下,第一种场景下,既然是用户重复提交导致的,那我们可以想办法让用户没办法重复提交。

方案一:前端控制

在前端做拦截,比如按钮点击一次之后就置灰或者隐藏。但是往往前端并不可靠,还是得后端处理才更放心。

方案二:Token机制

用户进入表单页面首先调用后台接口获取 token 并存入 redis,当用户提交表单时将 token 也作为入参,后端先删除 redis 中的 token,删除成功则保存表单数据,失败则提示用户重复提交。

img

这里为什么不先判断 redis 是否存在这个 token 再删除,是因为要保证操作的原子性,极端情况下,第一个请求查询到 redis 中存在这个 token,还没来得及删除,第二个请求进来,也查询到 redis 中存在这个 token,那么还是会造成重复提交的问题。

token 机制需要先请求获取 token 的接口,在有些情况下很明显并不合适。我们大部分请求都是要落到数据库的,所以我们可以从数据库着手。

方案三、唯一索引

这种方案就比较好理解了,使用唯一索引可以避免脏数据的添加,当插入重复数据时数据库会抛异常,保证了数据的唯一性。唯一索引可以支持插入、更新、删除业务操作。

方案四、悲观锁

这里所说的悲观锁是基于数据库层面的,在获取数据时进行加锁,当同时有多个重复请求时,其他请求都无法进行操作。悲观锁只适用于更新操作。

// 例如
select name from t_goods where id=1 for update;

注意:id 字段一定要是主键或者唯一索引,不然会锁住整张表,这是会死人的。悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用。

在请求量比较大的情况下,使用悲观锁明显不合适,这时候就到乐观锁上场了。

方案五、乐观锁

可以通过版本号实现,为表增加一个 version 字段,当数据需要更新时,先去数据库里获取此时的version版本号。

select version from t_goods where id=1

更新数据时首先要对比版本号,如果不相等说明已经有其他的请求去更新数据了,提示更新失败。

update t_goods set count=count+1,version=version+1 where version=#{version}

还有一种是通过状态机实现的,其实也是乐观锁的原理。这种方法适合在有状态流转的情况下,比如订单的创建和付款,订单的创建肯定是在付款之前,这时我们可以通过在设计状态字段时,使用 int 类型,并且通过值类型的大小来实现幂等性。

update t_goods set status=#{status} where id=1 and status<#{status}

同样,乐观锁也只适用于更新操作。

方案六、分布式锁

有时候我们的业务不仅仅是操作数据库,也可能是发送短信、消息等等,那数据库层面的锁就不适合了。这种情况下就要考虑代码层面的锁了,而 java 的自带的锁在分布式集群部署的场景下并不适用,那么就可以采用分布式锁来实现(Redis 或 Zookeeper)。

拿 Redis 分布式锁举例,比如一个订单发起支付请求,支付系统会去 Redis 缓存中查询是否存在该订单号的 Key,如果不存在,则以 Key 为订单号向 Redis 插入。查询订单是否已经支付,如果没有则进行支付,支付完成后删除该订单号的Key。通过 Redis 做到了分布式锁,只有这次订单支付请求完成,下次请求才能进来。当然这里需要设置一个Key 的过期时间,在发生异常的时候还要注意删除 Redis 的 Key。

总结

接口的幂等性是一个很常见的问题,需要根据具体业务场景的不同,选择合适的解决方案。

END

往期推荐

你必须了解的分布式事务解决方案

就这?分布式 ID 发号器实战

略懂设计模式之工厂模式

就这?Spring 事务失效场景及解决方案

就这?一篇文章让你读懂 Spring 事务

相关文章

  • 接口的幂等性的N种考虑

    分布式服务接口的幂等性如何设计 什么是幂等性 一个分布式系统中的某个接口,要保证幂等性,该如何保证?这个事儿其实是...

  • 如何保证接口的幂等性

    什么是幂等性 HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时...

  • 如何保证接口的幂等性?

    今天我们来聊聊关于接口的幂等性问题。 什么是幂等性 所谓幂等,就是任意多次执行所产生的影响均与一次执行的影响相同。...

  • 什么是接口的幂等性,如何实现接口幂等性?一文搞定

    每天一个知识点 什么是接口的幂等性,如何实现接口幂等性? (一)幂等性概念 幂等性原本是数学上的概念,用在接口上就...

  • 保证接口幂等性

    幂等性概念在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是...

  • 保证接口幂等性

    说到幂等性,应该很多人都知道这个词,顾名思义,就是无论操作多少次,产生的结果都是相等的。尤其是交易中,在开发过程中...

  • 高并发下,如何保证接口的幂等性?

    高并发下,如何保证接口的幂等性? 幂等性就是同一个操作执行多次,产生的效果一样。如 http 的 get 请求,数...

  • 问题整理

    怎样保证接口幂等性 @transational 有没有遇到失效的场景

  • Redis如何保证接口的幂等性?

    有个小伙伴在最近的一次业务升级中,遇到这样一个问题,我们设计了新的账户体系,需要在用户将应用升级之后将原来账户的数...

  • 冥等性

    编程中的幂等性(二):高并发的系统如何保证幂等性 - 阿官 - CSDN博客

网友评论

      本文标题:如何保证接口的幂等性?

      本文链接:https://www.haomeiwen.com/subject/stpciltx.html