NiceOffer

八股文解析

项目场景:如何设计秒杀系统?

系统设计秒杀高并发八股文

项目场景:如何设计秒杀系统?

一句话结论

  • 核心矛盾:瞬时高并发 vs 库存有限
  • 解决思路:前端限流 + 队列削峰 + Redis 预减库存 + DB 异步落库 + 兜底防超卖

面试标准答法

整体架构

用户 → CDN/前端 → 网关/限流 → 秒杀服务 → Redis(预减库存+排队)→ MQ → 订单服务 → MySQL

关键设计点

1. 前端与网关层

  • 静态页面 CDN 缓存,按钮置灰倒计时
  • 秒杀 URL 动态化,防提前刷单
  • 网关层令牌桶限流(如 1000 QPS),多余直接返回「已抢完」

2. Redis 预减库存

  • 活动前把库存加载到 Redis:stock:sku_123 = 100
  • 每次请求 DECR,返回值 < 0 则秒杀失败
  • 用 Lua 脚本保证「判断 + 扣减」原子性

3. 消息队列削峰

  • Redis 扣减成功后,发消息到 MQ(如 RocketMQ/Kafka)
  • 订单服务消费 MQ,异步创建订单、扣 DB 库存
  • 流量被 MQ 平摊,DB 压力可控

4. 数据库防超卖兜底

  • 乐观锁:UPDATE stock SET num = num - 1 WHERE sku_id = ? AND num > 0
  • 或唯一约束防重复下单:UNIQUE(user_id, activity_id)

5. 限流降级与隔离

  • 热点商品单独 Redis key + 本地缓存
  • 非核心功能(积分、通知)降级或延后
  • 秒杀服务独立部署,不拖垮主站

常见追问

追问要点
Redis 和 DB 库存不一致怎么办?Redis 只做预减,DB 为最终一致;未支付订单超时回滚 Redis
如何防刷子?验证码、滑块、IP 限频、用户风控、隐藏秒杀地址
为什么还要 MQ?削峰填谷,把瞬时 10w QPS 摊成 DB 能扛的 2k TPS
超卖怎么完全避免?Redis Lua + DB 乐观锁双重校验

面试回答模板(30 秒版)

延伸准备

  • 能画出秒杀时序图
  • 能解释为什么不用 DB 直接抗(行锁竞争、连接打满)
  • 能对比「悲观锁 vs 乐观锁 vs Redis 原子扣减」的取舍