支持防超卖的高并发秒杀系统关键架构如何设计?

2 个回答

  • 天魁
    我最喜欢自己仁至义尽后心安理得的无情无义。
    ## 作用 - 支撑秒杀开始时的突发高并发流量,避免应用、缓存、数据库被瞬时洪峰打垮。 - 通过库存原子扣减避免超卖,并通过异步订单、消息队列和对账机制保证最终一致性。 - 建立从前端、网关、应用、缓存到数据库的全链路防护,提升系统可用性。 ## 原理 - **分层拦截流量**:采用“多级缓存 + 全链路防护”,在前端、网关、服务层等逐层过滤无效请求,使只有少量请求进入核心链路和数据库。 - **热点限流**:使用 Sentinel 等限流组件对秒杀商品等热点参数进行限流,防止单个商品的突发流量耗尽系统资源。 - **Redis Lua 原子扣库存**:将“判断库存、扣减库存、记录占用”等操作放在 Lua 脚本中执行,利用 Redis 单脚本原子性避免并发扣减导致零超卖。 - **MQ 异步削峰**:库存预扣成功后,将下单请求发送到 RocketMQ,由消费者异步创建订单、操作数据库,把瞬时流量拉平为后端可处理的稳定流量。 - **缓存保护数据库**:通过 Redis 等缓存承载商品信息、库存查询和资格校验,减少数据库访问;同时防范缓存雪崩等问题。 - **最终一致性与补偿**:订单超时未支付时释放库存;通过消息重试、状态机和库存对账处理异常,避免少卖或数据不一致。 - **弹性与高可用部署**:服务无状态化,结合 K8s 弹性扩缩容应对流量洪峰;核心链路可结合异地多活等能力提升容灾能力。 - **架构按需演进**:可从单体架构逐步演进到分布式、微服务和云原生架构,根据流量规模引入限流、缓存、消息队列、服务治理和弹性编排。
    发布于 2026-10-29 15:51 •IP属地 安徽
    举报
    评论
    收藏

  • 冰心月
    世间万物,唯有过往伤人最深。
    ## 作用 该架构用于在高并发秒杀场景下: - 支撑商品详情和库存的海量读请求。 - 降低下单、扣库存产生的数据库写入压力。 - 防止多用户同时抢购导致超卖和库存不一致。 - 通过限流、隔离和异步处理,避免秒杀流量冲垮其他业务。 - 在请求链路各层逐步拦截无效请求,使最终到达数据库的请求尽量少。 ## 原理 ### 1. 分层拦截请求 按照客户端、接入层、应用层、缓存和数据库分层处理,让请求量从上到下逐步减少: - 客户端减少无效点击和重复请求。 - 接入层进行负载均衡和限流。 - 应用层做业务校验、缓存读、库存预扣和异步处理。 - Redis 承接高并发库存扣减。 - 数据库只处理最终有效的订单和库存变更。 ### 2. 客户端设计 #### 动静分离 - 商品图片、描述、JS、CSS 等静态内容提前静态化并放入 CDN。 - 设置合理缓存时间,更新后主动刷新 CDN。 - 价格、活动时间等动态数据通过 Ajax 异步获取。 - 服务端可对动态数据使用约 1 秒的短期本地缓存,数据变化时通过消息广播通知集群刷新。 #### 降低无效下单请求 - 非秒杀时间禁用下单按钮。 - 使用图形验证码、答题等方式拦截机器请求。 - 点击后禁用按钮并限制频率,例如 3 秒内只能提交一次。 - 可在后台提供开关,按活动风险动态启用限制策略。 ### 3. 接入层设计 - 使用 SLB/ALB 进行负载均衡,将流量分发到应用集群。 - 在接入层配置限流,超过下游处理能力的请求直接拒绝或快速失败。 - 限流阈值应通过压测确定,保证系统在可接受响应时间内运行。 - 当负载均衡层成为瓶颈时,可增加 SLB 实例并通过 DNS 轮询分散流量,或使用更高规格的负载均衡实例。 ### 4. 应用层隔离 - 将秒杀系统独立部署为微服务,避免与普通业务共用应用资源。 - 为秒杀业务配置独立数据库、缓存等资源。 - 订单、库存、商品等下游系统对来自秒杀系统的调用单独限流。 - 通过资源隔离和调用限流,防止秒杀高峰影响其他核心业务。 ### 5. 降低数据库读压力 - 商品信息、剩余库存等高频数据优先从本地缓存读取。 - 本地缓存可设置较短过期时间,例如 1 秒,以减少数据库查询。 - 缓存只用于提升读取性能,真正扣减库存时必须基于实时数据二次校验,避免短暂缓存延迟造成错误。 ### 6. 使用 Redis 预扣库存,降低写压力 - 秒杀开始前,将商品库存预加载到 Redis。 - 用户下单时先在 Redis 中执行原子扣减。 - Redis 扣减成功,才允许继续创建订单和更新数据库。 - Redis 库存不足时直接返回已售罄,不再请求数据库。 - 通过 `INCR`、`DECR` 等原子操作,把大量并发写请求拦截在内存缓存层,显著减少数据库行锁竞争。 ### 7. 防超卖机制 核心思路是“Redis 原子预扣 + 数据库最终校验/条件扣减”: 1. 活动前初始化库存到 Redis。 2. 下单请求通过用户、商品、活动等维度校验,防止重复下单。 3. 使用 Redis 原子操作扣减库存,保证同一时刻只有原子扣减成功的请求进入后续流程。 4. 扣减失败立即返回库存不足。 5. 扣减成功后再异步或同步创建订单,并更新数据库库存。 6. 数据库更新时仍应使用实时库存做条件判断,例如只在库存数量足够时更新,作为最终一致性保障。 7. 对订单失败、支付超时等场景,需要通过补偿任务回滚 Redis 和数据库库存。 ### 8. 异步削峰 - Redis 预扣成功后的订单创建、数据库更新等操作可通过消息队列异步处理。 - 消息队列将瞬时流量削成数据库可承受的平滑流量。 - 消费者按库存服务、订单服务的处理能力限速消费。 - 需要结合消息幂等、去重表或唯一业务键,避免消息重复导致重复下单或重复扣库存。 ### 9. 一致性与异常处理 - Redis 原子计数器负责高并发下的快速预扣。 - 数据库负责最终持久化和最终库存准确性。 - 本地缓存数据不能作为最终扣库存依据,只能用于展示和短时减压。 - 需要处理订单创建失败、消息丢失、消费失败、支付超时等异常。 - 可通过定时对账、库存补偿、订单状态回查等机制修正 Redis 与数据库之间的差异。 ## 关键结论 防超卖高并发秒杀系统的关键不是直接让所有请求扣数据库,而是: - 用 CDN、缓存解决读多写少; - 用客户端限制、接入层限流削减流量; - 用独立部署和资源隔离保护其他业务; - 用 Redis 原子扣减库存拦截绝大多数并发请求; - 用消息队列异步削峰; - 用数据库条件更新、幂等控制和库存补偿保证最终不超卖。
    发布于 2026-10-28 20:51 •IP属地 四川
    举报
    评论
    收藏