接口幂等性:确保分布式系统中接口调用结果的一致性

2024-09-14
来源:网络整理

1.接口调用问题

如今我们大部分系统都是分布式SOA或者微服务化,一个系统包含多个子系统服务,而一个子系统服务又经常会调用另外一个服务。服务调用服务无非就是用RPC通信或者,既然是通信,就有可能处理完返回结果的时候服务器就挂了,这时候用户发现好久都没有响应,就会多次点击按钮,这样就有了多次请求,数据处理的结果是不是应该统一?当然!特别是在支付场景。

2.什么是接口幂等性?

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

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

在增、删、改、查四个操作中,特别要注意增、改操作。

A:查询操作

查询不会改变结果,无论数据是否改变,查询结果都是一样的,是天然的幂等操作。

B:删除操作

删除一次或者多次都会删除该数据(注意返回结果可能不一样,如果删除的数据不存在则返回0,如果删除多条数据则返回多条结果,无论返回结果如何,删除操作也是幂等的)。

C:更新操作

大部分场景下修改结果都是一样的,但如果是增量修改,则需要保证幂等性,如下示例:

将表中id为XXX的记录的A字段的值设置为1。这个操作无论执行多少次都是幂等的。

将表中id为XXX的记录的A字段的值增加1,这不是幂等的。

D:添加新操作

添加重复提交场景下的幂等性问题,比如上面的支付问题

4.那么如何设计接口来实现幂等性呢?

两种常见的实现方案: 1.通过代码逻辑判断实现 2.利用机制实现 下面以支付系统为例,讲解并实现接口的幂等性。

A:通过代码逻辑判断实现接口幂等性,只能针对部分符合判断的逻辑实现,有一定的局限性

订单系统和支付系统用于用户购买商品;订单系统负责记录用户的购买记录以及订单的流转状态(),支付系统用于支付,提供以下接口。订单系统和支付系统通过分布式网络进行交互。

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

支付系统功能_新的支付系统_支付新系统是什么

本案例中,支付系统已经扣款了,但是订单系统因为网络问题还未得到准确结果,因此订单系统需要重试。从上图可以看出,支付系统并没有实现接口的幂等性,用户第一次和第二次调用订单系统都被扣了两次款,不符合幂等性原则(对于同一个订单,无论调用多少次,用户都只会被扣一次款)。如果需要支持幂等性,支付接口需要修改为如下接口:

支付(整数,整数,)

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

不同业务中不同的接口需要具有不同的幂等性,特别是在分布式系统中,当由于网络原因无法得到确定的结果时,往往需要支持接口幂等性。

随着分布式系统、微服务的流行,调用系统可能因为网络原因无法获取准确结果,从而导致重试。这就要求被调用系统具备幂等性。例如上文介绍的支付系统,对同一笔订单保证支付的幂等性,一旦确定该订单的支付状态,后续操作都会返回相同的结果,用户只会被扣款一次。该接口的幂等性在数据层面简化了操作:

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

当状态为0或者1时,从0到1的状态转换操作应该是幂等的,这种情况下执行操作前需要检查是否已经=1,如果已经=1,就返回true。

但是如果此时=2的话,订单状态0->1的时候,操作是不会成功,但是幂等性是针对同一个请求而言的,也就是保持了同一个幂等性。

然后执行

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

接口会返回失败,且不会对系统做任何修改。再次发送,结果是一样的,也不会对系统做任何修改。

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

机制实现步骤:

1、生成一个全局唯一的,放在jvm内存中,页面跳转的时候会获取,存进去,提交支付请求的时候优先获取。

2、提交后,后台验证,执行提交逻辑,提交成功后删除内容,生成新的更新。这样,第一次提交后,如果页面有更新,再次提交删除的内容,页面就会提交失败。

特点:需申请、一次性有效、可限量

注意:使用操作进行判断,删除成功即表示验证通过,如果使用+进行验证,会有并发问题,不建议使用

[本文]将持续更新...另外,作者还提供了多年来精心编撰的各类计算机专业的视频教程,例如,...

分享