「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
什么是幂等?
多次执行所产生的影响均与一次执行的影响相同。
幂等问题出现的常见原因
- 用户重复提交:这个是最常见的,前端后端都需要进行限制
- mq消息重发:小概率事件,但是也需要注意
- 网络重发:小概率事件,但是也需要注意
- 系统间重试:这个也比较常见,不少rpc框架都支持配置重试策略
幂等问题的控制关键
在技术实现上,控制幂等问题的关键在于唯一键+状态机。
- 首先,调用者在请求中携带一个唯一ID,这个ID唯一的标识一个工作单元,这个工作单元只允许被成功执行一次。
- 其次,接受者在收到请求,获得唯一ID时,要先去查询这个ID所标识的工作单元是否被执行过。 检查是否执行的逻辑通常是根据唯一请求ID ,在服务端查询请求是否有记录,是否有对应的响应信息,如果有,直接把响应信息查询后返回;如果没有,那么就当做新请求去处理。
如何实现幂等?
- 乐观锁 更新数据时先去判断版本号是否一致,如果不一致,则无法对数据进行更新。例子:
update order set count= count+1, version=version+1 where id=1 and version=1
-
悲观锁 分布式锁或者select for update等锁
-
状态机控制 和版本号有点类型,通过状态去判断能不能更新数据。如:订单状态分为已创建(10),已支付(20),已发货(30),已完成(40),已取消(50),取消订单时,状态必须<30才能取消
update order set status=50 where id=1 and status<30
- 去重表 去重表的机制是根据mysql唯一索引的特性来的实现幂等,具体流程:
- 首先客户端先请求服务端,服务端先将这次的请求信息存入一张mysql的去重表中,这张表要根据这次请求的其中某个特殊字段建立唯一索引,或者主键索引。
- 判断是否插入成功
- 如果插入成功,则继续做后续业务请求。
- 如果插入失败,则代表已经执行过当前请求。
- TOKEN机制
这种机制就比较重要了,适用范围较广,有多种不同的实现方式。
主要思想:为每一次操作生成一个唯一性的凭证,也就是token。一个token在操作的每一个阶段只有一次执行权,一旦执行成功则保存执行结果。对重复的请求,返回同一个结果。\
- 可通过redis去实现token的生成
- 业务执行前先去获取token,服务器会把token保存到redis中。
- 携带token调用业务请求。
- 服务器判断token是否存在redis中,存在表示第一次请求,这时把redis中的token删除,继续执行业务。
- 如果判断token不存在redis中,就表示是重复操作,直接返回重复标记,这样就保证了业务代码,不被重复执行。
- select + insert 最简单的处理方式,先查询一些关键数据,判断是否已经执行过,未执行的话进行业务处理,已执行,直接返回成功 (不适于并发请求)
总结
实现幂等的方式有很多种,还是需要根据具体业务去选择不同的实现。