【浅谈幂等】
幂等
- 概念介绍
- 具体场景
- 解决方案
- 总结
#
系统在复杂的【网络环境】和【不可控的人为操作因素】下,往往会产生重复操作的场景。为保障【系统整体的健壮】,我们会要求相关操作结果无论受到多少次**重复调用**,也都返回**相同的响应结果**。
概念介绍
名词解释:幂等源自于数学,如f(x)=f(f(x)),后用作计算机概念,表示相同参数多次调用依旧返回相同结果。
常数函数是最简单的幂等函数,如f(x)=2,无论多少次调用,函数结果都是2。这类比翻译成计算机程序就是常见的select操作(排除复合操作的场景:如两次select中有一次修改。即便出现该场景,业务逻辑上也认为重复操作的select满足幂等,后续的select重复操作也都只会返回最新结果)。
具体场景
- 表单流程提交:由于网络抖动响应延迟等原因导致流程表单提交按钮无响应,用户着急重复点击导致同一张流程多次发起。
- 订单支付扣款:类似的,同一份订单用户重复请求支付导致多次付款,不保证幂等客服感觉要被CALL到怀疑人生了。
- 消息广播推送 :给一万个客户推送一条大促的广告,推送程序异常导致重复推送,同一条信息在同一个用户的手机端重复刷屏。客户嫌烦直接把你软件给卸载了。
- 消息消费:分布式系统上下游模块利用消息通讯,数据流转也要求幂等,避免接收处理来自上游系统(消息中间件)重复下发的消息。
- 并发库存超卖:还有一种情况是并发控制没做好导致同一时间仅剩的1库存卖给了n个客户
- 定时任务耗时事务:比如事务中含有耗时磁盘操作,缓存读写,db读写。一个事务还未执行完又重复触发一轮计算。
解决方案
- 状态机幂等:在后端层面,【表单流程提交】等类似单据问题可以使用状态机幂等方案。同一张单据号在同一个操作界面只会产生一个【单据状态】。如果状态机已然处理下一个状态,后台接口收到上一个状态的变更,理论上是不允许实际的数据层操作变动的。
- 读后写:数据写入的时候,先根据关键字在db进行查询,如果存在,则直接返回。
- DB唯一索引:无论同个应用进程里多线程触发重复操作还是分布式部署的多个应用进程触发重复操作,保证DB唯一性约束后就能保证程序应用无法重复插入数据。但要求业务应用逻辑实现对应的DuplicateKeyException的友好处理。不过仅限于单表单库的场景
- token申请机制:请求前约束,同一个请求表单页面只会请求申领一个token,后端页面只会处理一次token(单次失效)。假设网络延迟表单无响应,多次点击提交请求,所携带参数还是之前的token,后端是不会重复处理失效token的请求的。
- 锁机制:使用乐观锁或者悲观锁保障不会出现并发重复提交的问题。定义好锁粒度把出现锁竞争的请求失效掉即可。
- 幂等接口调用:第三方提供幂等接口,允许传入来源和序列号。相同系统来源和业务序列号标示一个唯一请求,多次发送同一请求,第三方系统也只会处理一次。
总结
无论是锁/索引/读后写/token/幂等api的来源与序列号,本质都是保证业务唯一“票据”在并发重复操作中可以被识别,区别在于使用场景和实现方式。
- 并发不高情况下可以视情况select then insert + 锁。
- 并发高时考虑source+seq等方式进行限流只处理其中的有效请求或者上锁失效竞争请求。
系统交互不复杂的时候可以使用token申领或者db索引限制的方式。
by mori.wang
还没有评论,来说两句吧...