关于防重,我是这么设计的

几年前,设计了一套增值服务购买流程,当时设计一整套下单购买流程。当时看了我们项目中多个订单防重,发现都不一样。结合了一点自己的思考,设计了一整套流程。当时感觉没什么,面试一问全扒瞎,特此回顾一下。

重复提交是项目中最常遇到的一个问题。为啥?不好界定啊,比如

  • 用户就是要买两单,手速快了点,防重了就不合适。
  • 大商户就是要用工具刷,就突出一个合理。
  • 前端忘记防抖,没辙。
  • 接口失败重试,机制就是这个机制
  • 队列重复消费了,也算是一种吧

会造成哪些问题呢?

  • 比如重复扣减库存?
  • 比如多加积分?
  • 比如重复下单?

场景还有很多,一般核心的业务场景都是要做预防的,具体哪些就要根据业务场景来考虑了

至于怎么解决,首先有两个概念,防重和幂等

  • 防重:防止重复提交,对于结果没有严格要求
  • 幂等:通俗点来说是防重的子集,再防重的基础上要求返回的结果一致

实际场景分&析解决方案

一个精简版的下单流程就是下面这个样子,下面就根据这个场景来聊一下防重。不谈场景就谈方案都是***!!!!

就拿上面的场景来说,我标注的三个地方都有可能发生重复提交的场景

  • 场景1:客户端重复网络抖动,前端重复提交,页面重复进入。此处的重复提交基本上都和客户端和网络还有用户脱不了关系
  • 场景2:可能得点就是重复消费,失败重复调用的场景。此处防重一般是第三方来考虑,稍后我也会分析分析。
  • 场景3:这个场景多半就是失败重试了。跟第三方,最大努力通知相关。

场景1 的解决方案

  1. client处理

一般来说,前端要做到流程不回退,防抖等操作,这个很重要,可以解决很大一部分重复请求

  1. 服务端处理
  • 带上token

请求的时候,可以前端台上token,或者后台提供token服务来解决这个问题,此token要保证特定时间内唯一性

  • 活锁CAS

如果不使用token也不使用redis,可以通过cas改变修改其他表的状态或者库存的方式,如果成功,才进行后续的订单创建

场景2 的解决方案

这个场景一般是三方服务要考虑的场景了,根据我对接调试的经验,一般是一种。

每次请求都生成一个订单,保证订单id唯一。每次请求都是新的一单,不会乱,出现问题也都是调用方的问题。一般的支付渠道也都是一次请求一单。

但是不能防止恶意请求的方式,为了解决这个问题,三方都会带上非对称加解密的方式进行请求校验。

场景3 的解决方案

第三个场景呢,也是在支付的时候会遇到的情况。有的支付渠道防控做的不大好,就是会有重复调用的情况。关键通知的时间不可控,一般来说是10分钟,20分钟,xxxxx进行累加。时间跨度比较大,也比较容易。

  • 根据己方或者三方订单号进行查询,判断,这种可以防止时间跨度比较大的情况
  • 唯一索引进行兜底,避免并发情况。

总结

当时设计的时候,防重部分,参考了项目中的蛮多案例的。这里只把一个下单流程中防重的点拿出来分析,适用性比较广。方案算不上高大上,但是适用性还可以,我觉得可以cover大部分场景,。

  • 前端需要保证下单后流程不回退
  • 唯一token校验防止重复
  • 依赖于上游服务校验防止重复
  • 每次下单都生成一单
  • 唯一索引
相关推荐
Easonmax35 分钟前
用 Rust 打造可复现的 ASCII 艺术渲染器:从像素到字符的完整工程实践
开发语言·后端·rust
百锦再40 分钟前
选择Rust的理由:从内存管理到抛弃抽象
android·java·开发语言·后端·python·rust·go
小羊失眠啦.43 分钟前
深入解析Rust的所有权系统:告别空指针和数据竞争
开发语言·后端·rust
q***71851 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
大象席地抽烟1 小时前
使用 Ollama 本地模型与 Spring AI Alibaba
后端
程序员小假2 小时前
SQL 语句左连接右连接内连接如何使用,区别是什么?
java·后端
小坏讲微服务2 小时前
Spring Cloud Alibaba Gateway 集成 Redis 限流的完整配置
数据库·redis·分布式·后端·spring cloud·架构·gateway
方圆想当图灵2 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(下)
分布式·后端·github
方圆想当图灵2 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(上)
分布式·后端·github
小羊失眠啦.3 小时前
用 Rust 实现高性能并发下载器:从原理到实战
开发语言·后端·rust