什么是幂等性?
调用方对系统进行重复的调用,不管调用多少次,调用对系统的影响都是相同的。系统默认认为外部系统调用失败是常态,失败之后会有重试。
什么情况下会导致幂等性问题?
- 网络波动,可能引起重复请求
- 用户重复操作,可能导致触发多次请求。
- 业务接口调用的失败重试
- 页面重复刷新
- 用户双击按钮,导致重复提交
- 消息队列消费失败重试。
保持幂等性有什么不足?
幂等性虽然简化了客户端的操作,但是以服务端逻辑变为复杂为代价,除非有特殊业务要求,否则,尽量不要保证幂等行
- 增加了保证幂等性的业务逻辑,增加了业务代码的复杂度
- 并行代码改为了串行代码,降低了代码的执行效率
如何解决幂等性问题
- 查一下上次执行状态,没有则进行第一次的请求
- 在服务状态改变前,增加放置重复提交的逻辑
- token机制解决幂等性问题
- token机制可能存在的问题
- 先执行业务再删除token时
- A执行完业务,还没有删除缓存,B请求到达携带token通过验证
- 加拍他锁,保证执行业务和删除缓存为原子操作
- 利用redis的原子指令incr,以token作为key,进行自增,保存时为1,第一次请求返回结果为2,则正常请求,否则,为重复请求。
- A执行完业务,还没有删除缓存,B请求到达携带token通过验证
- 先删除token,再执行业务
- 如果第一次请求超时,或者执行失败,没有响应,第二次请求重试时,认为重复请求,没法执行。
- 一个token代表一个请求,可以返回接口异常,客户端重新获取token请求服务端。
- 如果第一次请求超时,或者执行失败,没有响应,第二次请求重试时,认为重复请求,没法执行。
- 先执行业务再删除token时
- token机制缺点
- 每次业务请求都要多一次token的请求,成千上万的请求中只有十几个是失败的,为了少量的失败,增加一次请求是一种资源的浪费。
- token机制可能存在的问题
- 乐观锁机制
数据库增加一个version字段,更新前判定版本号,版本号为预期版本号就执行更新,否则更新失败。或者加一个时间戳字段,更新时校验时间戳
- 适合更新场景
- 缺点:
- 对数据库有压力
- 代码侵入性
- 业务复杂时,可能存在ABA问题(版本号自增)。
- 缺点:
- 悲观锁机制解决幂等性
每次去操作数据时,都觉得别人中途会修改,所以每次在拿数据的时候都会上锁,加锁,再配合事务解决幂等性问题。
-
适用更新场景
-
查询条件必须是索引,不然会锁表
-
锁住记录,别的请求只能等待,事务太长,影响性能。
-
select + insert+update (主键或者唯一标识)
如果重复概率低,可以直接insert+唯一标识(主键)捕捉异常返回成功。 -
状态机幂等
- 有些数据存在多种状态,可以利用状态机来处理幂等。
- 有些数据存在多种状态,可以利用状态机来处理幂等。
-
防重表去重
建一种去重表,然后使用唯一索引,将更新语句与操作去重表的逻辑放在一个事务里面,异常会回滚
- 分布式锁幂等
请求过来时,先去尝试获得分布式锁,如果获得成功,就执行业务逻辑,反之获取失败的话,就舍弃请求直接返回成功