接口的幂等性原则

简介: 接口的幂等性原则

接口调用存在的问题


现如今我们的系统大多拆分为分布式SOA,或者微服务,一套系统中包含了多个子系统服务,而一个子系统服务往往会去调用另一个服务,而服务调用服务无非就是使用RPC通信或者restful,既然是通信,那么就有可能在服务器处理完毕后返回结果的时候挂掉,这个时候用户端发现很久没有反应,那么就会多次点击按钮,这样请求有多次,那么处理数据的结果是否要统一呢?那是肯定的!尤其在支付场景。


什么是接口幂等性



接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...,这就没有保证接口的幂等性


什么情况下需要保证接口的幂等性



在增删改查4个操作中,尤为注意就是增加或者修改,


A: 查询操作


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


B: 删除操作


删除一次和多次删除都是把数据删除。(注意可能返回结果不一样,删除的数据不存在,返回0,删除的数据多条,返回结果多个,在不考虑返回结果的情况下,删除操作也是具有幂等性的)


C: 更新操作


修改在大多场景下结果一样,但是如果是增量修改是需要保证幂等性的,如下例子:


把表中id为XXX的记录的A字段值设置为1,这种操作不管执行多少次都是幂等的

把表中id为XXX的记录的A字段值增加1,这种操作就不是幂等的


D: 新增操作


增加在重复提交的场景下会出现幂等性问题,如以上的支付问题


  1. 那么如何设计接口才能做到幂等呢?


常见的两种实现方案: 1. 通过代码逻辑判断实现 2. 使用token机制实现 下面以支付系统为例,分别对接口的幂等性进行说明与实现


A: 通过代码逻辑判断实现接口幂等性,只能针对一些满足判断的逻辑实现,具有一定局限性


用户购买商品的订单系统与支付系统;订单系统负责记录用户的购买记录已经订单的流转状态(orderStatus),支付系统用于付款,提供如下接口,订单系统与支付系统通过分布式网络交互。


boolean pay(int accountid,BigDecimal amount) //用于付款,扣除用户的


这种情况下,支付系统已经扣款,但是订单系统因为网络原因,没有获取到确切的结果,因此订单系统需要重试。由上图可见,支付系统并没有做到接口的幂等性,订单系统第一次调用和第二次调用,用户分别被扣了两次钱,不符合幂等性原则(同一个订单,无论是调用了多少次,用户都只会扣款一次)。如果需要支持幂等性,付款接口需要修改为以下接口:


boolean pay(int orderId,int accountId,BigDecimal amount)


通过orderId来标定订单的唯一性,付款系统只要检测到订单已经支付过,则第二次调用不会扣款而会直接返回结果:


在不同的业务中不同接口需要有不同的幂等性,特别是在分布式系统中,因为网络原因而未能得到确定的结果,往往需要支持接口幂等性。


随着分布式系统及微服务的普及,因为网络原因而导致调用系统未能获取到确切的结果从而导致重试,这就需要被调用系统具有幂等性。例如上文所阐述的支付系统,针对同一个订单保证支付的幂等性,一旦订单的支付状态确定之后,以后的操作都会返回相同的结果,对用户的扣款也只会有一次。这种接口的幂等性,简化到数据层面的操作:


update userAmount set amount = amount - 'value' ,paystatus = 'paid' where orderId= 'orderid' and paystatus = 'unpay'


其中value是用户要减少的订单,paystatus代表支付状态,paid代表已经支付,unpay代表未支付,orderid是订单号。


在上文中提到的订单系统,订单具有自己的状态(orderStatus),订单状态存在一定的流转。订单首先有提交(0),付款中(1),付款成功(2),付款失败(3),简化之后其流转路径如图:


当orderStatus = 1 时,其前置状态只能是0,也就是说将orderStatus由0->1 是需要幂等性的


update Order set orderStatus = 1 where OrderId = 'orderid' and orderStatus = 0


当orderStatus 处于0,1两种状态时,对订单执行0->1 的状态流转操作应该是具有幂等性的。这时候需要在执行update操作之前检测orderStatus是否已经=1,如果已经=1则直接返回true即可。


但是如果此时orderStatus = 2,再进行订单状态0->1 时操作就无法成功,但是幂等性是针对同一个请求的,也就是针对同一个requestid保持幂等。


这时候再执行


update Order set orderStatus = 1 where OrderId = 'orderid' and orderStatus = 0


接口会返回失败,系统没有产生修改,如果再发一次,requestid是相同的,对系统同样没有产生修改。


B: 使用token机制实现接口幂等性,通用性强的实现方法


token机制实现步骤:



1. 生成全局唯一的token,token放到redis或jvm内存,token会在页面跳转时获取.存放到pageScope中,支付请求提交先获取token


2. 提交后后台校验token,执行提交逻辑,提交成功同时删除token,生成新的token更新redis ,这样当第一次提交后token更新了,页面再次提交携带的token是已删除的token后台验证会失败不让提交


token特点:   要申请,一次有效性,可以限流


注意: redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用


目录
相关文章
|
9月前
接口幂等性设计
接口幂等性设计
95 1
|
SQL 缓存 NoSQL
接口的幂等性设计和防重保证,详细分析幂等性的几种实现方法
本篇文章详细说明了幂等性,解释了什么是幂等性,幂等性的使用场景,讨论了幂等和防重的概念。分析了幂等性的情况以及如何设计幂等性服务。阐述了幂等性实现防重的几种策略,包括乐关锁,防重表,分布式锁,token令牌以及支付缓冲区。
7176 0
接口的幂等性设计和防重保证,详细分析幂等性的几种实现方法
|
9月前
|
存储 缓存 安全
接口的幂等性
接口的幂等性
85 0
|
3月前
|
设计模式 缓存 前端开发
什么是幂等性?四种接口幂等性方案详解!
本文深入分布式系统中的幂等性问题及其解决方案,涵盖数据库唯一主键、乐观锁、PRG模式和防重Token等方法,关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
什么是幂等性?四种接口幂等性方案详解!
|
4月前
|
数据库
什么是接口幂等性?如何保证接口幂等性?
接口幂等性(Idempotency)是指同样的请求被重复执行多次,产生的结果与执行一次的结果相同。换句话说,接口无论被调用一次还是多次,系统的最终状态保持不变。
475 5
|
6月前
|
缓存 NoSQL Java
接口幂等该如何设计和实现
本文探讨了程序开发中常见的重复操作问题,如多次点击生成多余订单或支付、RPC调用失败后的重试机制滥用及非法重复请求等。通过接口幂等性设计可有效解决这类问题,确保相同请求多次执行结果一致无副作用。文章详细解释了幂等性的概念及其重要性,并提供了具体的设计与实现方法,包括使用唯一标识符、设计幂等操作、事务处理及缓存策略。此外,还讨论了实现幂等性接口所带来的好处,如并发请求处理、失败请求管理及系统集成等,并提出了验证接口幂等性的策略。通过这些技术和方法的应用,可以显著提升系统的稳定性和用户体验。
156 1
|
6月前
|
SQL 索引
分布式之接口幂等性
分布式之接口幂等性
57 2
|
8月前
|
数据库 API 网络架构
浅谈应用接口的幂等性
【6月更文挑战第2天】本文介绍幂等性是计算和网络通信中的重要概念,确保同一操作执行多次不会改变结果。在数据库操作中,查询、删除(同一数据)和特定更新是幂等的,而插入和累加更新不是。幂等性和安全性(如GET、HEAD等方法)确保多次请求无副作用,对涉及金钱的操作尤为重要。
95 0
|
前端开发 NoSQL Java
什么是接口幂等性?为什么会产生接口幂等性问题?如何保证接口幂等性?
什么是接口幂等性?为什么会产生接口幂等性问题?如何保证接口幂等性?
305 0
什么是接口幂等性?为什么会产生接口幂等性问题?如何保证接口幂等性?
|
SQL NoSQL Java
【项目场景】如何保证接口的幂等性?
【项目场景】如何保证接口的幂等性?
498 0

热门文章

最新文章