幂等性
幂等性
什么是幂等性
幂等概念来自数学,表示N次变换和1次变换的结果是相同的。在业务开发的时候幂等的概念有所不同。在业务开发说的幂等性更多指的是接口的幂等性,
即:客户端对服务器的多次请求只要有一次对资源产生了影响,其他所有的请求则都不应该对资源(一般指的是存放的数据)产生影响,
产生影响这个词是很不好下定义的,具体是否对资源产生了影响需要根据实际的业务场景来看,比如我现在购物网站上下单了,但是网络不好,搞心态。我很生气就一直狂点,但是后台生成的订单只能一条,不会因为我多点了就多生成。
一般情况下,幂等性的问题的产生一般有
- 网络的问题导致重复请求
- 用户的重复操作
- 采用了服务调用超时重试
什么情况下需要幂等性
首先申明不是所有的服务都需要幂等性,具体要根据实际的业务来,某些业务多次请求对资源产生影响是没什么问题的,比如 update activity set take_count =1 where id = 1 以及select语句,使用这个sql的业务就完全不用考虑,或者说他天然支持幂等,
那么什么情况下需要幂等性,一般来说当业务要求资源不能因为外部的多次调用而多次改变转态的时候,就要考虑幂等性的设计。很显然,声明幂等的服务认为,外部调用者会存在多次调用的情况,为了防止外部多次调用对系统数据状态的发生多次改变,将服务设计成幂等。
常见的幂等性解决方案
设计幂等性接口的核心在于:执行业务操作之前首先去查询上一次的执行状态如果已经执行完,则直接返回不执行业务,反之执行,幂等需要通过唯一的业务单号来保证。也就是说相同的业务单号,认为是同一笔业务。使用这个唯一的业务单号来确保,后面多次的相同的业务单号的处理逻辑和执行效果是一致的。
建防重表
基于mysql唯一索引
- 建立一张去重表,其中某个字段需要建立唯一索引
- 客户端去请求服务端,服务端会将这次请求的一些信息插入这张去重表中
- 因为表中某个字段带有唯一索引,如果插入成功,证明表中没有这次请求的信息,则执行后续的业务逻辑
- 如果插入失败,则代表已经执行过当前请求,直接返回
加分布式锁
基于Redis的SETNX命令实现
- 客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段
- 将该字段以 SETNX 的方式存入 redis 中,并根据业务设置相应的超时时间
- 如果设置成功,证明这是第一次请求,则执行后续的业务逻辑
- 如果设置失败,则代表已经执行过当前请求,直接返回
获取token
通过token 机制实现接口的幂等性,
具体流程步骤:
- 客户端会先发送一个请求去获取 token,服务端会生成一个全局唯一的 ID 作为 token 保存在 redis 中,同时把这个 ID 返回给客户端
- 客户端第二次调用业务请求的时候必须携带这个 token
- 服务端会校验这个 token,如果校验成功,则执行业务,并删除 redis 中的 token
- 如果校验失败,说明 redis 中已经没有对应的 token,则表示重复操作,直接返回指定的结果给客户端
注意:
- 对 redis 中是否存在 token 以及删除的代码逻辑建议用 Lua 脚本实现,保证原子性
第一次请求先获取token,第二次之后携带访问,没有携带的就不执行
文章参考