1、幂等性,是指多个(或多个)请求对资源没有副作用(比如查询数据库,但不添加、删除、修改它,所以对数据库没有影响)。
2.幂等性还包括第一次请求对资源有副作用,但是后续的请求不会对资源产生副作用。
3、幂等性关注的是后续的多个请求是否会对资源产生副作用,而不是结果。
4.网络超时等问题不属于幂等性的讨论范围。
幂等性是系统服务对外界做出的一个承诺(而非实现),承诺只要接口调用成功,多次外部调用对系统的影响是一致的。声明为幂等的服务会认为外部调用失败是正常的,失败后必然会重试。
什么时候需要幂等性?
在业务开发中,经常会遇到重复提交的情况,无论是由于网络问题导致无法收到请求结果而重新发起请求,还是前端操作抖动导致重复提交。在交易系统和支付系统中,此类由重复提交导致的问题尤为明显,例如:
1、若用户在APP上连续多次点击提交订单,后台只应生成一个订单;
2.向支付宝发起支付请求。由于网络问题或者系统bug,支付宝应该只扣一次钱。显然,声明为幂等的服务认为外部调用者会进行多次调用。为了防止多次外部调用多次改变系统数据状态,服务被设计为幂等的。
幂等性与反重复性
上面例子中小明遇到的问题只是重复提交,这和服务幂等性的初衷不同。重复提交是指在第一次请求已经成功的情况下,手动进行了多次操作,导致不满足幂等性要求的服务多次改变状态。幂等性更多的用在第一次请求结果未知(比如超时)或者异常失败的情况下,为了多次确认第一次请求是否成功而发起多次请求,而不会因为多次请求而导致多次状态改变。
什么时候需要保证幂等性?
以 SQL 为例,有以下三种场景,只有第三种场景需要开发者使用其他策略来保证幂等性:
1.col1 FROM tab1 WHER col2=2,无论执行多少次,状态都不会改变,是天然的幂等性。
2、tab1 SET col1= col2=2,这个操作无论执行多少次成功,状态都是一致的,所以也是一个幂等操作。
3. tab1 SET col1=col1+ col2=2,每次执行结果都会变,不是幂等的。
为什么要设计幂等服务?
幂等性可以简化客户端逻辑处理,但代价是服务逻辑更加复杂。要满足幂等性要求,服务逻辑至少要包含两点:
1.首先查询上次的执行状态,如果没有,则认为是第一次请求。
2.服务改变状态的业务逻辑前,确保防止重复提交的逻辑

幂等性的缺点
幂等性本意是简化客户端逻辑处理,但增加了服务提供方的逻辑和成本,是否有必要需要根据具体场景分析,因此除非有特殊业务需求,尽量不要提供幂等性接口。
1.增加了控制幂等性的额外业务逻辑,使得业务功能复杂化;
2、将并行执行功能改为串行执行,降低了执行效率。
确保幂等性策略
幂等性需要通过唯一的业务订单号来保证,也就是说,同一个业务订单号被认为是同一个业务,通过这个唯一的业务订单号来保证同一个业务订单号的处理逻辑和执行效果是一致的。以支付为例,在不考虑并发的情况下,实现幂等性很简单: ① 首先检查订单是否已经支付。 ② 如果已经支付,则返回支付成功;如果还未支付,则继续支付流程,并将订单状态改为已支付。
防重复提交策略
上述幂等保证方案分为两步,步骤2依赖于步骤1的查询结果,无法保证原子性。高并发下会出现这样的情况:第二个请求到来时,第一个请求的步骤2的订单状态还未变为“已付款状态”。既然得出了这个结论,剩下的问题就变得简单了:锁定查询和状态更改操作,将并行操作改为串行操作。
乐观锁定
如果只是更新已有数据,没必要锁定业务。在设计表结构的时候使用乐观锁,一般都是用 来做乐观锁,既能保证执行效率,又能保证幂等性。例如:tab1 SET col1=1,=+ =## 但是乐观锁可能会失效,也就是所谓的ABA问题。但如果一直是自增的,就不会出现ABA。(我在网上找了一张图可以很好的说明乐观锁,这里引用一下,支持一下乐观锁)
抗重桌
使用订单号作为去重表的唯一索引,每次请求都根据订单号往去重表中插入一条数据。第一个请求是查询订单支付状态,当然这个订单还没有支付,就执行支付操作,不管成功失败,执行完后就更新订单状态为成功或者失败,同时删除去重表中的数据。后续的订单由于表中唯一索引的原因,无法插入,直到第一个请求完成(成功或者失败),才返回操作失败。可见,防重表是有锁的功能的。
分布式锁
这里用到的防重表可以用分布式锁来代替,比如当一个订单发起支付请求时,支付系统会检查缓存中是否存在该订单号的key,如果不存在就增加该订单号的key,检查该订单付款是否已经支付,如果还没有支付则进行支付,支付完成后删除订单号的key。通过实现分布式锁,只有当这个订单的支付请求完成后,下一个请求才能进来。相比去重表,将并发放入缓存中,效率更高。思路是一样的,同一时刻只能完成一个支付请求。
代币
这种方式分为两个阶段:申请阶段和支付阶段。第一阶段,在进入订单提交页面之前,订单系统需要根据用户信息向支付系统发起申请请求,支付系统会将其保存在缓存中,用于第二阶段支付。第二阶段,订单系统拿到申请的支付请求,支付系统会查看缓存中是否存在,如果存在则说明是第一次发起支付请求,删除缓存后才开始支付逻辑处理;如果缓存中不存在则说明是非法请求,其实这就是一个,支付系统用来确认你是你妈的子。缺点是需要系统间进行两次交互,流程比上面的方式复杂一些。
付款缓冲
快速受理所有订单的支付请求,快速受理订单的缓冲管道。后续使用异步任务处理管道中的数据,过滤掉重复的待支付订单。优点是同步转异步,吞吐量高。缺点是无法及时返回支付结果,后期需要监控支付结果的异步返回。
来源: