分布式系统如何保证接口幂等性解析
1、简介
接口幂等性,就是说一个接口,多次发起同一个请求,保证接口的结果是准确的。
比如,订单系统调用支付系统进行支付,因为网络超时原因,订单系统发起了两次支付请求,因为负载均衡算法落在了不同的机器上,造成一个订单扣款两次,就尴尬了。
保证幂等性主要是三点:
- 对于每个请求必须有一个唯一标识。
- 每次处理完请求之后,必须有一个记录标识这个请求处理过了。
- 每次接受请求需要进行判断之前是否处理过。比如一个订单已经支付过了,就已经有了一条流水,如果重复发送这个请求此时插入支付流水,订单id已经存在了,唯一键约束,报错插不进去。保证接口幂等性。
对于如何保证接口幂等性,还需要在实际工作中,结合自己的业务。
2、保证接口幂等性常见方案
-
业务表内唯一索引
比如你要对创建销售出库单的接口保证幂等性,即保证一个订单只能有一个对应的销售出库单。
销售出库单表里面,可以针对销售出库单表中的订单id,创建一个unique key唯一索引,如果接口重试,两次创建同一个销售单,一定会违反唯一索引,报错。
这种方案常见于插入
,并且这个数据在数据库中只能有一条数据。 -
业务表内状态机
比如订单状态一般有待支付、待发货、已发货等等状态,修改订单状态只能依次按顺序,不能从待付款直接到已发货状态,比如说将订单状态修改为待发货的时候。
update order set status = “待发货” where status = “待支付” and id = 1,订单的状态其实就变为了“待发货”。假如说id = 1的订单接口重复调用,又要执行一次这个操作的话,就不会生效了,就不会再次修改了。 -
基于版本号的更新
一般不常用
,对于接口调用方来说,要多做一些事情,他要先查出来数据的version,调用修改接口的时候,传过去这个version。 -
基于mysql的去重表/基于redsi的去重
这个方案是很常见的一个方案。
将所有的参数拼接成一个字符串,或者是从这些入参里选择一些参数,可以唯一标识这一次请求。
如果基于mysql
,单独搞一个表出来,就一个字段,建一个唯一索引,插入数据到表里去,如果这个接口被重复调用的话,再次插入一个表的话,唯一索引会报一个冲突出来,这次插入就会失败。
这个方案还是不错的
,尤其是并发不是特别高的话,接口被调用的并发不是特别高的话,每秒的并发请求量在1000左右,1000以内的话,用mysql的去重表也没什么问题。
但是如果接口调用量很大,并发很高,一秒请求量达到了几十万,选择使用redis
,拼接一个串出来,直接set设置到redis里去,如果下一次人家请求再过来了,此时会发现这个key已经存在了,那么这个时候就不能执行了,因为已经出现重复调用了。