写文章

幂等性学习及接口的幂等性

2019-09-15 15:52:55

75 | 0 | 0

幂等性学习


一:什么是幂等性

在这里需要有以下几个问题需要注意:

1:幂等性的实质是一次或多次请求同一个资源,其结果是相同的。其关注的是对资源产生的影响(副作用)而不是结果,结果可以不同。比如列表查询的时候,一边在save或者是update,而你这边还是在select,其结果肯定是不同的,但是你的select操作并未对数据(资源)产生影响(副作用);

2:幂等性不仅仅只是一次或者多次请求的时候对资源没有副作用。比如根据id对数据库的查询操作,此操作对数据库没有增删改,所以多次查询操作对数据库结果是没有任何影响的;

3:幂等性还包括了第一次请求资源的时候,对资源产生了副作用,但是在以后多次同样的请求操作的时候,都不会在对资源产生副作用了。比如我们根据id更新订单状态从支付中变为支付完成这个操作,在执行第一次的时候,会更新为支付完成。之后在根据这个id执行此操作,无论执行多少次其结果和第一次执行后的结果一样;

4:幂等性关注的是以后的多次请求是否对资源产生了副作用,而不是关注的结果;

5:需要说明的是网络超时、服务宕机等问题,不是幂等的范围。

幂等性是系统服务对外的一种承诺(注意,是一种承诺,而不是一种实现),接口服务提供方承诺只要调用接口成功了,外部多次调用对系统的影响是一致的。这里需要强调一点就是,声明为幂等的服务会认为调用方调用失败是常态,是正常业务,并且允许在调用失败后必然会有重试的。

来源:凯哥Java(kaigejava)



二:什么情况下需要使用幂等

    在我们开发中,经常会遇到一个头疼的事情—重复提交的情况。重复提交情况有多种原因产生的。如由于网络问题无法收到请求结果情况下而重新发起的请求或者是因为调用方前端操作抖动而造成的重复提交。

重复提交操作带来的严重后果在交易系统、支付系统中因重复提交而产生的问题尤其的明显。如:我们发起支付的时候向支付宝支付请求,无论是交易系统自身bug还是交易系统与支付宝之间的网络问题导致重复发送,支付宝应该并且必须只能扣用户一次钱的。在这种需求下的系统在设计的时候,我们就需要将系统或者服务设计成幂等的。

三:幂等和防重复提交比较

重复提交:重复提交是在第一次请求成功的情况下,人为的进行多次操作,从而导致不满足幂等性要求的服务多次改变数据状态。

幂等:更多使用的情况是第一次请求知道结果(比如常见的网络抖动导致连接超时)或者失败异常情况下,发起多次请求的,其目的是多次确认第一次请求成功,却不会因为多次请求而出现多次的状态变化。

什么情况下需要保障幂等性?

在这里,我们以sql为例来讲解。在下面三种场景中,只要第三种场景需要开发人员使用其他策略来保障幂等性:

1:查询情况

Select * from table where id = 2

无论执行多少次都不会对资源造成副作用,所以可以说是天然的幂等

2:根据id更新

Update table set status =1 where id =2

无论执行成功多少次状态都是一致的,第一次执行成功对资源造成的副作用和多次执行成功对数据造成的副作用是一样的。因此可以说这种场景也是幂等操作

3:不是幂等情况

Update table set version = version+1 where id = 2

每次执行的结果都会发生变化,也就是说对资源造成了副作用,这种不是幂等的。这种情况如果想要保证幂等,语句可以这么写:update table set version = version+1 where id = 2 and version = 1.这样就可以保证幂等了。

为什么要设计幂等性的服务?

幂等性的服务可以使得客户端的处理业务逻辑变的简单了,但是确实以牺牲服务端逻辑变复杂为代价的。因为在满足幂等服务的需求下逻辑至少需要包含以下两点:

1:首选去查询上一次的执行状态(结果),如果没有则认为是第一次请求。这样就增加了业务难度

2:在服务改变状态的业务逻辑前,保证防重复提交的逻辑

幂等的不足:

通过上面我们知道了幂等服务是以牺牲服务提供者逻辑和成本为代价的。所以,是否有必要,需要根据具体场景具体来分析的。因此除了业务上的特殊要求外,尽量不要提供幂等的接口。

1:增加了额外的控制幂等的业务逻辑,复杂了业务功能;

2:把并行执行的功能改为串行执行,这样就降低了执行的效率。

保证幂等策略

其实在保证幂等的业务会通过唯一的业务单号来保证的。也就是说相同的单号,被认为是同一笔业务。使用唯一的业务单号来确保,后面多次相同的业务单号的的处理逻辑和执行兄啊过是一致的。我们以常见的支付为例(在不考虑并发情况下),实现幂等很简单:

1:先查询一下订单是否已经支付过

2:如果已经支付过,则返回支付成功;如果没有支付,在进行支付流程操作后,将订单状态修改为已支付。

0

收藏
分享