如何设计一个秒杀系统
你好,我是阿彬。今天我们来聊一聊秒杀系统。
设计一个秒杀系统(Flash Sale System)是系统架构设计中的经典挑战。其核心矛盾在于:极短时间内的高并发读写与有限库存之间的冲突。
为了保证系统不崩溃、数据不超卖,我们需要从“流量削峰”、“缓存抗压”和“数据一致性”三个维度来设计。

核心架构原则
在动工之前,必须遵循以下四个原则:
- 读多写少:尽量通过缓存解决。
- 请求拦截:越靠前的环节,拦截掉越多的无效流量。
- 异步处理:削减瞬时峰值,保护底层数据库。
- 高可用:核心链路要隔离,避免秒杀挂了导致全站瘫痪。
关键技术方案
阶段一:动静分离(前端拦截)
秒杀页面通常包含大量静态资源(图片、CSS、JS)。
- 静态化:将秒杀详情页静态化并部署在 CDN。
- 请求频率限制:在前端做“按钮置灰”,防止用户疯狂点击。
- 动态隐藏:秒杀开始前,下单接口 URL 是加密或隐藏的,防止脚本抢购。
阶段二:负载均衡与网关隔离
- 独立域名:给秒杀业务独立的二级域名,部署独立的集群。
- 限流:在网关层(Nginx/Sentinel)使用令牌桶或漏桶算法,超过阈值的请求直接返回“抱歉,已售罄”。
阶段三:缓存扣减(核心环节)
千万不要直接去数据库扣库存。 数据库抗不住几万并发的 Row Lock。
- 库存预热:活动开始前,将库存数量加载进 Redis。
- 原子扣减:使用 Redis 的
DECR操作或 Lua 脚本。Lua 脚本可以保证“查询-判断-扣减”的原子性,彻底杜绝超卖。
阶段四:异步下单(MQ 削峰)
一旦 Redis 扣减库存成功,立即向用户返回“抢购中”,而不是直接返回成功。
- 消息队列(Kafka/RocketMQ): 将订单信息发送到 MQ,后端服务再根据自身处理能力,平滑地消费消息进行写库操作。
- 流量削峰:MQ 充当了蓄水池的作用,保护了最脆弱的数据库。
防超卖与高一致性方案
| 环节 | 方案 | 目的 |
|---|---|---|
| Redis Lua | if stock > 0 then decrement |
保证内存级别不超卖 |
| 数据库唯一索引 | 用户 ID + 活动 ID 建立联合唯一索引 | 防止同一个用户下多单 |
| 数据库乐观锁 | UPDATE table SET stock = stock - 1 WHERE id = x AND stock > 0 |
兜底安全,确保库存不为负 |
容灾与兜底策略
- 服务降级:压力过大时,关闭非核心功能(如评价、物流查询)。
- 熔断:如果下单链路某个节点响应过慢,直接断开,防止雪崩。
- 黑名单:针对异常 IP 和 User-Agent,直接在 WAF 层拦截。
如何设计一个秒杀系统
https://liuyuhe666.github.io/2026/03/28/如何设计一个秒杀系统/