1. 设计目标
- 高并发处理能力:支撑十万级 QPS 的瞬时流量冲击
- 严格防超卖:确保商品库存不被超额扣减
- 最终一致性保障:Redis 与数据库之间允许短暂不一致,但需可靠收敛
- 低延迟响应:核心路径(如库存扣减)控制在毫秒级
- 系统可降级:在 Redis 故障或流量异常时,具备熔断与兜底机制
2. 架构分层策略
2.1 前端防护层
- 静态资源托管:秒杀页面采用纯静态 HTML + CDN 分发,彻底剥离后端渲染压力
- 请求合法性校验 :
- 用户需提前获取一次性秒杀 Token(由后端签发,含用户 ID、活动 ID、时间戳、签名)
- Token 有效期极短(如 1~3 秒),防止重放攻击
- 结合设备指纹(如 canvas、WebGL、UserAgent 特征哈希)识别异常客户端
- 交互限制:按钮点击后立即置灰,前端禁止重复提交
2.2 网关限流层
- 全局限流:基于令牌桶算法(如 Guava RateLimiter 或 Sentinel)控制入口总流量
- 用户级限流:对同一用户 ID 实施"1 秒 1 次"请求频率限制(可通过 Redis INCR + EXPIRE 实现)
- 异常流量拦截:集成风控系统,自动封禁高频 IP 或设备 ID
2.3 防刷与安全机制
- 图形验证码:在秒杀前触发滑块/点选验证码(仅对可疑流量或高并发时段启用,避免影响正常用户)
- 限购策略:每人最多购买 N 件(通过 Redis 记录用户已购数量)
- 黑名单机制:对历史作弊用户/设备/IP 实施永久或临时封禁
3. 核心库存扣减方案(Redis 主路径)
3.1 预热与原子操作
-
秒杀开始前,将商品库存预加载至 Redis(如
stock:product_123 = 100) -
扣减操作通过 Lua 脚本 保证原子性,脚本逻辑如下:
lualocal stock = tonumber(redis.call('GET', KEYS[1])) if stock > 0 then redis.call('DECR', KEYS[1]) return 1 -- 扣减成功 end return 0 -- 库存不足 -
同时记录用户购买状态(如
user_bought:user_456:product_123 = 1),防止重复下单
3.2 异步订单生成
- 扣减成功后,向 消息队列(如 Kafka / RocketMQ) 发送下单消息
- 下游订单服务消费消息,写入数据库订单表,并更新 DB 库存(最终一致性)
- 订单表设计包含唯一索引(如 user_id + product_id),确保幂等性
3.3 多级缓存
- L1 缓存(本地缓存):缓存活动配置(如开始时间、限购数),减少 Redis 访问
- L2 缓存(Redis):承载核心库存数据与用户购买状态
4. 数据库分片方案(DB 主路径,作为备选或特定场景)
4.1 分片策略
- 将 100 件库存逻辑拆分为 10 个 DB 分片(如按 user_id % 10 路由)
- 每个分片独立维护子库存(如
shard_0.stock = 10) - 并发请求被分散到不同分片,消除单行锁竞争,提升整体吞吐
4.2 优势与局限
| 优势 | 局限 |
|---|---|
| 无需 Redis,天然强一致 | 无法实时获取全局剩余库存 |
| 单分片内 ACID 保证不超卖 | 分片扩容困难,需预估容量 |
| 无缓存-DB 对账复杂度 | 热点用户仍可能集中在某一分片 |
适用场景:对一致性要求极高、且可接受库存统计延迟的业务(如金融类秒杀)
5. Redis 与 DB 一致性保障
- 采用 "延迟双删" 策略:
- 删除 Redis 缓存
- 更新数据库
- 延迟 N 毫秒(如 500ms)后再次删除缓存(应对主从同步延迟)
- 增强方案 :通过 MQ 异步触发缓存删除
- 若删除失败,进入指数退避重试(1s, 2s, 4s...)
- 重试 3~5 次仍失败,转入死信队列,告警并人工介入
- 定期对账任务:每日离线比对 Redis 库存、订单表、DB 库存,自动修复差异
6. 容灾与降级机制
6.1 Redis 故障应对
- 熔断策略:当 Redis 连接失败率超过阈值,立即熔断 Redis 路径
- 降级方案 :
- 方案 A:直接返回"秒杀繁忙,请稍后再试",保护 DB
- 方案 B:切换至 DB 分片模式(若已部署),但限流至极低 QPS(如 100/s)
- 禁止直连 DB 扣库存:避免 DB 被高并发写请求压垮
6.2 Redis 快速恢复
- 高可用部署:Redis Cluster + 哨兵(Sentinel)实现自动主从切换
- 容器化运维:K8s 自动重启故障 Pod,配合健康检查
- 缓存预热脚本 :服务启动时,从 DB 批量加载热点商品库存至 Redis,避免缓存击穿
7. 总结:双模架构选型建议
| 场景 | 推荐方案 |
|---|---|
| 极致性能 + 可接受最终一致 | Redis 主路径 + MQ 异步落库 |
| 强一致性 + 中低并发 | DB 分片方案 |
| 混合部署 | Redis 为主,DB 分片为灾备降级路径 |
通过 Token 防重 + 网关限流 + Lua 原子扣减 + MQ 异步解耦 + 多级容灾,构建高可用、可扩展、防超卖的秒杀系统。