接口幂等性设计

一个操作一次执行的结果和多次执行的结果一致。

问题引出

常见场景

1、订单创建接口,第一次调用超时了,然后调用方重试了一次
2、在订单创建时,我们需要去扣减库存,这时接口发生了超时,调用方重试了一次
3、当这笔订单开始支付,在支付请求发出之后,在服务端发生了扣钱操作,接口响应超时了,调用方重试了一次
4、一个订单状态更新接口,调用方连续发送了两个消息,一个是已创建,一个是已付款。但是你先接收到已付款,然后又接收到了已创建
5、在支付完成订单之后,需要发送一条短信,当一台机器接收到短信发送的消息之后,处理较慢。消息中间件又把消息投递给另外一台机器处理

出现的本质

  • 前端重复提交
  • 接口超时重试
  • 消息重复消费

http请求的幂等

  • GET

    天生幂等,多次请求不会变更数据,只是每次请求返回的数据结果不同而已。

  • POST

    每次请求会产生新的数据,所以不是幂等的

  • PUT

    • 增量更新:不幂等

      ​ 每次更新时,如果不存在记录,则增加一条数据

    • 存量更新:幂等

      ​ 因为每次存量更新时,目的是为了把数据更改到某个状态。

  • DELETE

    每次操作的目的是删除数据,对数据结果产生的作用是一致的,所以是幂等的

注意,仅仅通过请求方式去判断幂等性在不同的业务场景下也不是完全正确的。

解决方案

  • 数据库唯一索引

  • token + redis

    提交数据前, 获取token,提交时携带token,后端进行token校验判断,是否是重复提交

  • 乐观锁

  • 状态机控制

    订单状态更新,应为状态不可逆,也就是说,欲更新为付款状态的订单,当前状态必须是未付款

  • 分布式锁

  • 全局唯一ID