秒杀

如何设计出健壮的秒杀系统?

在电商大促、新品首发、限量抢购等场景中,秒杀系统是技术架构中最具挑战性的模块之一。它需要在极短时间内应对海量用户请求,同时保证系统的稳定性、数据的一致性以及用户体验的流畅性。

一、秒杀系统的本质与核心挑战

秒杀的本质是:短时间内集中爆发的超高并发写操作,最终落到数据库的更新操作上。其典型特征包括:

  • 时间短:通常只有几分钟甚至几秒钟。
  • 并发高:瞬时QPS可达数十万甚至百万级。
  • 流量不均:99%的请求可能是无效或重复的。
  • 资源有限:库存数量极少(如100件),极易发生超卖。

核心挑战有哪些?

挑战 说明
🔴 超卖问题 库存被扣成负数,导致商品多卖,损害公司利益
🟠 高并发冲击 大量请求瞬间涌入,压垮服务器、缓存、数据库
🟡 缓存击穿 热点Key失效,请求直接打到DB
🔵 接口刷单 黑产使用脚本自动化抢购,破坏公平性
🟣 秒杀URL泄露 提前获取接口地址,绕过前端限制提前抢购
⚪ 服务雪崩 秒杀拖垮整个系统,影响其他正常业务

二、健壮秒杀系统的设计原则

设计秒杀系统的核心思想是:尽可能把流量挡在离数据库最远的地方,通过层层过滤和削峰填谷,让最终到达数据库的请求是可控且有效的。

我们遵循以下五大设计原则:

  1. 前置化处理:尽量在前端或边缘节点完成校验和拦截。
  2. 动静分离:静态资源独立部署,减少后端压力。
  3. 异步化流程:非关键路径异步执行,提升响应速度。
  4. 限流降级:保护系统不被压垮,牺牲部分功能保核心可用。
  5. 数据隔离:秒杀业务独立部署,避免影响主站。

三、秒杀系统架构设计(现代版)

  					+------------------+
                    |   CDN / Edge     | ← 静态页面、JS、图片加速
                    +------------------+
                              ↓
                    +------------------+  
                    |     Nginx        | ← 反向代理、负载均衡、IP限流
                    +------------------+
                              ↓
                    +------------------+  
                    |   API Gateway    | ← 统一入口、鉴权、限流、熔断
                    +------------------+
                              ↓
         +------------------------------------------+
         |               Service Layer              |
         | +----------------+  +----------------+   |
         | | 限流服务       |  | 验证码服务       |   |
         | | (Token Bucket) |  | (滑块/短信)     |   |
         | +----------------+  +----------------+   |
         | +----------------+  +----------------+   |
         | | Redis预减库存   |  | 下单队列        |   |
         | | (Lua脚本原子操作)|  | (RabbitMQ/Kafka)|   |
         | +----------------+  +----------------+   |
         +------------------------------------------+
                              ↓
                    +------------------+
                    |    MySQL         | ← 分库分表 + 乐观锁
                    +------------------+

四、关键技术方案详解

1️⃣ 防止超卖:Redis + 乐观锁 + 预减库存

目标:确保库存不超卖,且高性能

  • 预减库存:秒杀开始前,将商品库存预热到 Redis 中,例如 SET goods:1001:stock 100

  • 原子扣减:使用 Lua 脚本保证“判断库存 + 扣减”原子性:

  • 1
    2
    3
    4
    5
    local stock = redis.call('GET', KEYS[1])
    if not stock then return -1 end
    if tonumber(stock) <= 0 then return 0 end
    redis.call('DECR', KEYS[1])
    return 1
    

数据库最终扣减:异步消费队列时,再用 乐观锁 更新数据库:

1
2
UPDATE goods SET stock = stock - 1, version = version + 1 
WHERE id = ? AND stock > 0 AND version = ?

2️⃣ 防止URL泄露:动态化秒杀链接

目标:防止用户通过F12查看Network提前发起请求

  • 秒杀开始前不暴露真实接口地址。

  • 用户进入页面 → 请求获取“秒杀令牌” → 后台返回加密URL(如 /seckill/act_xxx)。

  • URL可带时效性(如5秒过期),MD5或JWT签名防篡改。

  • 1
    2
    GET /api/seckill/token?goodsId=1001
    → 返回 { "url": "/seckill/execute/abc123", "expire": 5 }
    

3️⃣ 动静分离 & 页面静态化

目标:减少后端计算压力

  • 商品详情页、倒计时、按钮状态等生成静态HTML(如用 FreeMarker、Vue SSR)。
  • 前端通过 AJAX 获取实时数据(如剩余库存、是否已抢完)。
  • 静态资源托管在 CDN,全球加速。

📌 好处:90%的流量被CDN承接,不经过应用服务器。

4️⃣ 接口限流:多层级防护

目标:拦截无效请求,防止系统崩溃

(1)前端限流

  • 按钮点击后禁用5秒,防止连点。
  • 前端增加随机延迟,打散请求洪峰。

(2)Nginx 层限流

1
2
3
4
limit_req_zone $binary_remote_addr zone=seckill:10m rate=10r/s;
location /seckill {
    limit_req zone=seckill burst=20 nodelay;
}

(3)网关层限流(推荐)

  • 使用 令牌桶算法(Token Bucket)漏桶算法(Leaky Bucket)
  • 工具推荐:Guava RateLimiter、Sentinel、Redis + Lua
1
2
3
4
5
6
7
// Guava 示例
RateLimiter limiter = RateLimiter.create(1000); // 每秒1000个令牌
if (limiter.tryAcquire(500, TimeUnit.MILLISECONDS)) {
    // 处理请求
} else {
    // 限流,返回“请求过于频繁”
}

(4)用户级限流

  • userIddeviceId 限制单位时间内的请求次数(Redis计数器)。

5️⃣ 防刷机制:人机识别 + 行为分析

目标:识别并拦截黄牛和脚本

  • 验证码:滑块、点选、短信验证码(秒杀前触发)
  • 行为分析:监测请求频率、鼠标轨迹、页面停留时间
  • 设备指纹:识别同一设备多账号刷单
  • 黑名单机制:对恶意IP/设备进行封禁

📌 建议:验证码在“提交订单”环节触发,而非一开始就弹出,提升用户体验。

6️⃣ 异步下单 & 削峰填谷

目标:平滑流量峰值,提升系统吞吐量

  • 成功通过预减库存的请求,写入消息队列(如 Kafka、RabbitMQ)。
  • 后台消费者异步处理下单逻辑(创建订单、扣数据库库存、发短信通知)。
  • 用户立即返回“正在处理”,前端轮询结果或WebSocket推送。

📌 好处:

  • 将瞬时高峰转化为平缓的后台任务流。
  • 即使下游系统短暂不可用,消息队列也能缓冲压力。

7️⃣ 服务降级与熔断

目标:系统异常时仍能提供基本服务

  • 使用 HystrixSentinel 实现熔断降级。
  • 当下单服务异常时,自动切换到“排队中”页面或提示“稍后再试”。
  • 关键服务独立部署,避免连锁故障。

📌 示例降级策略:

  • Redis宕机 → 返回“活动太火爆,请稍后再试”
  • DB压力大 → 暂停新订单,继续处理队列中已有请求

8️⃣ 数据库优化:分库分表 + 读写分离

目标:支撑高并发写入

  • 秒杀订单表按 orderIduserId 分库分表(如ShardingSphere)。
  • 使用MySQL主从架构,写走主库,读走从库。
  • 冷热分离:历史订单归档,提升查询性能。

五、完整秒杀流程图

六、总结:构建健壮秒杀系统的 Checklist

类别 关键措施
防超卖 Redis预减 + Lua原子操作 + DB乐观锁
抗高并发 CDN + Nginx + Redis集群 + 消息队列
防刷 动态URL + 验证码 + 用户限流 + 设备指纹
系统稳定 服务降级 + 熔断 + 监控告警
体验优化 页面静态化 + 异步下单 + WebSocket通知
数据安全 秒杀独立数据库 + 分库分表 + 备份机制

七、结语

秒杀系统不是简单的“抢购功能”,而是一套涉及前端、网络、缓存、中间件、数据库、安全、监控的综合性高并发架构工程。

设计秒杀系统的关键在于:提前预判风险,层层设防,把复杂留给自己,把简单留给用户

随着技术发展,越来越多的公司开始采用 Serverless 架构边缘计算AI反作弊 等新技术来进一步优化秒杀体验。但万变不离其宗——流量控制、资源隔离、数据一致,依然是我们永恒的主题。

Java Geek Tech wechat
欢迎订阅 Java 技术指北,这里分享关于 Java 的一切。