接口的幂等性

什么是幂等性?

幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。

幂等函数或幂等方法是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。

什么是接口幂等性?

对于同一个接口的多次调用结果和一次调用结果应该是相同的

为什么要实现幂等性?

某些场景由于业务处理或者操作不当导致多次调用与一次调用结果不一致,比如支付场景,对于一个订单的支付最终只需要成功一次,如果对于同一个订单支付成功了两次,这就出了问题。

相应的需要幂等性的场景:

  • 前端重复提交表单: 在填写一些表格时候,用户填写完成提交,很多时候会因网络波动没有及时对用户做出提交成功响应,致使用户认为没有成功提交,然后一直点提交按钮,这时就会发生重复提交表单请求。
  • 用户恶意进行刷单: 例如在实现用户投票这种功能时,如果用户针对一个用户进行重复提交投票,这样会导致接口接收到用户重复提交的投票信息,这样会使投票结果与事实严重不符。
  • 接口超时重复提交:很多时候 HTTP 客户端工具都默认开启超时重试的机制,尤其是第三方调用接口时候,为了防止网络波动超时等造成的请求失败,都会添加重试机制,导致一个请求提交多次。
  • 消息进行重复消费: 当使用 MQ 消息中间件时候,如果发生消息中间件出现错误未及时提交消费信息,导致发生重复消费

引入幂等性后对系统有什么影响?

对于有幂等性需求的场景,增加了幂等性会保证系统的数据正常,避免因幂等性问题引发的数据异常。

但是也同时增加了系统的复杂度,这就需要我们依据实际场景来判断是否要引入幂等性。

Restful API 接口幂等性

  • GET:幂等的,对于同一个资源,多次请求获取到的都是相同的资源。
  • POST:非幂等,用于创建资源,多次执行可能会创建多个相同的资源。
  • PUT:区分场景来判断是否幂等,用于更新资源,对于同一个资源的相同的更新多次执行结果都是一样的,是幂等的,但是对于累加更新操作,是非幂等的。
  • DELETE:区分场景来判断是否幂等,用于删除资源,如果是对于唯一主键资源的删除,那多次删除和一次删除的结果是一样的,是幂等的,如果是带条件的删除,那么多次删除有可能会删除新增的资源,删除的结果就不一样了,非幂等。

实现幂等性的方案

数据库唯一主键

数据库表中设置唯一主键,可以保证同样的数据只会存在一条,而唯一主键也应该使用分布式ID。

适用操作

新增、删除

使用限制

需要生成分布式ID

主要流程

  1. 客户端请求服务器端,服务器端生成分布式ID返回给客户端
  2. 客户端带着分布式ID,请求服务器端新增资源
  3. 服务器端使用分布式ID作为表唯一主键插入数据,插入成功说明没有重复,插入失败说明有重复数据

数据库乐观锁

数据库乐观锁适用于资源更新,在需要更新的表中新增版本标识字段,如version,每次更新都会以该版本作为条件进行更新。

适用场景

更新

使用限制

在表中需要新增版本标识字段

主要流程

  1. 首先线程A查询当前需要更新的记录其版本标识为1,线程B也查询该记录其标识为1
  2. 线程A进行更新,更新条件包括版本标识为1,将版本标识更新为2
  3. 线程B也进行更新,更新条件包括版本标识为1,将版本标识更新为2
  4. 线程A先更新成功,将版本标识更新为了2,此时线程B因为版本标识已经变更了,导致更新失败,这就是乐观锁

防重 Token 令牌

针对客户端连续点击或者调用方的超时重试等情况,例如提交订单,可以使用分布式Token作为全局唯一标识,服务器接收到请求后判断Token是否存在,如果存在则继续执行业务,如果不存在则说明该Token已经被使用过了,报错。

适用场景

  • 插入操作
  • 更新操作
  • 删除操作

使用限制

  • 需要生成分布式唯一Token
  • 需要引入分布式缓存redis

主要流程

  1. 请求分布式唯一Token,服务器端将Token存入redis并设定失效时间
  2. 带着Token请求接口执行业务逻辑,删除Token,如果能删除成功则说明Token存在,继续执行业务,如果删除失败, 报错(这里要保证原子性,先查询再删除Token是两步操作)

下游传递唯一序列号

所谓请求序列号,其实就是每次向服务端请求时候附带一个短时间内唯一不重复的序列号,该序列号可以是一个有序 ID,也可以是一个订单号,一般由下游生成,在调用上游服务端接口时附加该序列号和用于认证的 ID。

当上游服务器收到请求信息后拿取该 序列号 和下游 认证ID 进行组合,形成用于操作 Redis 的 Key,然后到 Redis 中查询是否存在对应的 Key 的键值对,根据其结果:

  1. 如果存在,就说明已经对该下游的该序列号的请求进行了业务处理,这时可以直接响应重复请求的错误信息。
  2. 如果不存在,就以该 Key 作为 Redis 的键,以下游关键信息作为存储的值(例如下游商传递的一些业务逻辑信息),将该键值对存储到 Redis 中 ,然后再正常执行对应的业务逻辑即可。

适用场景

  • 插入操作
  • 更新操作
  • 删除操作

使用限制

  • 需要下游三方传递唯一序列号
  • 需要引入redis

主要流程

  1. 首先下游自己生成唯一序列号,请求上游的时候带上序列号
  2. 上游查询序列号加上认证ID拼接后在redis中是否存在,如果存在说明该请求已经处理过,重复了,报错
  3. 如果不存在,则将此序列号加上认证ID拼接存入redis,继续执行业务

总结

幂等性问题在分布式系统中很常见,有些业务场景必须保证接口幂等性,如支付、订单等,所以要根据具体业务需求来实现幂等性。

本文给出的幂等性方式有四种

  1. 数据库唯一主键方案
  2. 更新场景下的数据库乐观锁方案
  3. 防重Token方案
  4. 上下游场景中传递唯一序列号方案

参考文章

https://www.cnblogs.com/aspirant/p/11628654.html

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值