幂等设计
最后更新于
最后更新于
先介绍幂等定义、原因——然后介绍支付中的幂等——再介绍各种幂等方法——最后介绍自定义注解的好处【抽象,复用】 【】
【产生原因:https://www.cnblogs.com/coderacademy/p/18082540】
【解决方案:】
定义:一个操作,连续执行多次所产生的结果与仅执行一次的效果相同原因:在分布式系统里,只要下游服务有写(保存、更新)的操作,都有可能会产生幂等性问题。比如说网络原因波动、用户快速点击、超时重试机制、定时任务、重复消费、高并发\
客户端防抖
服务端进行校验
前端防抖:
提交请求后禁用按钮【并没有从系统设计层面解决问题】
RPG(POST/Redirect/GET) 模式
POST 请求重定向到 GET 请求再展示页面,刷新操作只会重复 GET 请求,而不是 POST 请求
适合表单提交后展示结果页面,如:订单创建、发表评论
业务代码实现:
状态机:比如订单表中有下单、已支付、完成、撤销等状态,可以通过限制状态的流动来完成幂等。【最好的,但是只适用于有限状态流转的场景,不适合通用幂等需求,而且状态更新需要依赖数据库,存在潜在的锁竞争】
Token:这里的token是客户端生成的(相当于在前端用js生成的【为什么不用就直接说token放在客户端不太安全】
自定义注解 + Redis【更加灵活通用性强,自定义幂等键唯一标识,适合支付接口】
通过 JVM 提供的内置锁如 Lock/synchronized 【只适用单机模式,服务重启无法保持】
分布式锁:直接在数据库上加锁的做法性能不够友好,可以使用分布式锁redis的setnx【锁过期、高并发影响性、库存扣减等场景】
布隆过滤器/bitmap:适用于是否存在的幂等性判断,一定误判率:
乐观锁思想:通过版本号或时间戳等机制判断数据是否已被修改
数据库实现:
insert语句前先select:简单但效率低
悲观锁 select... for update:行锁保证但效率低
乐观锁 加入version:
唯一索引:可以捕获异常,数据库压力大
放重表:维护成本高(例如消息消费中,创建防重表,存储消息的唯一ID,消费时先去查询是否已经消费,已经消费直接返回成功。)\
【支付业务场景:https://blog.csdn.net/qq_67786627/article/details/132719662】
对于同一笔交易的多次提交,只会产生一次支付结果,并且对账单和余额不会重复扣减 支付流程操作:用户选择支付方式 -> 跳转到收银台 -> 用户支付成功 ->第三方支付平台回调 -> 修改订单状态\
重复支付的产生:支付成功和第三方支付平台回调
用户支付时,若微信支付失败或网络问题导致支付状态不明,转用支付宝或其他方式支付,或短时间内多次点击支付,可能导致同一订单被重复扣款。
用户支付后,支付状态需依赖第三方平台(如微信、支付宝)的异步回调通知。网络问题可能导致后端未能正确接收支付状态,造成订单状态错误
解决方法:
前端防抖
token令牌
引入支付中的状态,但是后端需要加上主动查询逻辑,防止回调失败