接口设计之幂等性

Posted 风暴之林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了接口设计之幂等性相关的知识,希望对你有一定的参考价值。

接口幂等性的重要性

最近看到一个线上问题,意识到API设计要考虑很多,其中包括接口幂等性。

列举几个场景,突出本文核心思想。

场景1:请求正确执行了支付操作,但因为网络的原因,没有拿到支付结果,于是再去请求支付,造成重复支付。 场景2:恶意请求退款等操作,重复退款等。 场景3:对于一些异步回调的系统服务,重复处理回调结果。

分布式系统及微服务下,因为网络原因而导致调用系统未能获取到确切的结果从而导致重试,这就需要被调用系统接口具有幂等性。

何为接口幂等性

简单的说接口幂等性,就是执行一次请求,和执行多次请求所产生的结果是一致的。

哪些操作需要保证接口幂等性

  • 查询,查询一次和查询多次,在数据不变的情况下,查询结果是一样的。select是天然的幂等操作。

  • 删除,一般的删除操作后,对应数据就不在了,多次删除也不会有其他影响。

  • 新增/更新,如表单重复提交,重复支付,需要幂等操作,否则会带来严重后果。

如何设计幂等性接口

后端接口

自己总体思路是依靠全局唯一性ID和mysql的排他锁,自定义乐观锁,主键唯一性等等。

1.依靠业务逻辑的判断

依靠业务逻辑的判断,如支付场景下,支付前取订单号判断是否已经支付,未支付则进行后续支付操作。当A,B两个请求达到系统请求支付接口,若A请求获取到状态已经支付,则成。 若获取到的状态都是未支付,此时一个线程,执行update操作(排它锁):

 
   
   
 
  1. update t_order set status = 1 where order_id = 123 and status = 0

支付操作是事物的,当B去执行update失败后,我们进行回滚。

2.分布式锁

在分布式场景下,我们可以使用分布式锁(由redis或zookeeper实现)来实现幂等。 比如使用redis,依靠KEY+订单号的唯一性,请求接口时get(KEY+订单号),进行支付状态判断。但此方法对于高并发下,仍有可能会存在请求AB同时拿到可支付状态的情况,此时还需要依赖数据层面,mysql的悲观锁,或者自定义版本号version字段实现乐观锁。

3.排重表

大体思路:依赖Mysql主键唯一性,将唯一业务单号作为主键插入,实现互斥。

前端方面

  • 对于普通用户的操作的一些高危的操作,前端页面上,做表单重复提交,N秒内限制重复提交,做友好提示,使穿过到后端的请求尽量有效。

开放平台API设计思考

自己工作涉及开放平台API,所以多多少少会去关注API的设计。

API设计时的思考方向

  • 接口的命名、请求参数命名、出入参格式等

  • 是否需要依赖于第三方和外系统,对外系统可能的影响

  • 接口是否拆分、接口的扩展性

  • 接口是否需要幂等

  • 防刷、接口限流、降级

  • 是否需要缓存、缓存穿透怎么办

  • 白名单

  • TPS、并发数、响应时长。

---end---


以上是关于接口设计之幂等性的主要内容,如果未能解决你的问题,请参考以下文章

细说Restful API之幂等性

微服务架构之幂等性问题及设计思想,你不得不知的一些幂等方案

编程思想之幂等性一编程之道

kafkaKafka 事务性之幂等性实现

聊聊接口幂等性设计

聊聊接口幂等性设计