目录一、业务需求二、整体架构分层从上到下层层削峰1CDN 层挡静态流量2Nginx 网关层第一道拦截3API 网关层Spring Cloud Gateway4应用服务层多级拦截核心过滤无效请求5Redis 层核心热点存储6RocketMQ/Kafka 消息队列削峰异步7MySQL 数据库层兜底订单超时取消三、核心问题解决方案1、超卖问题重中之重2、少卖问题3、热点 key 大 Key 问题Redis4、高可用保障5、防黄牛四、完整业务执行流程五、性能指标三高目标六、可选优化进阶七、面试高频坑点总结秒杀核心痛点瞬间海量请求、超卖、数据库压力雪崩、流量打垮服务、恶意请求、库存一致性。三高高并发、高可用、高性能额外还要保证数据一致性、防超卖。整体思路分层拦截把流量尽可能挡在上游保护 DB热点数据放缓存异步削峰分布式锁控制库存。一、业务需求商品定时开启秒杀限定库存数量用户限抢 1 件不能超卖也不能少卖大流量下系统不雪崩响应快防止重复下单、黄牛刷接口最终订单落库库存扣减准确。二、整体架构分层从上到下层层削峰CDN → Nginx网关层 → 限流防刷 → API网关 → 应用服务层 → Redis缓存层 → MQ消息队列 → 数据库MySQL1CDN 层挡静态流量商品静态页面、图片、倒计时页面全部放 CDN秒杀页面不要后端实时渲染减少回源请求。2Nginx 网关层第一道拦截IP 限流单 IP QPS 限制抵御爬虫黑名单拉黑恶意 IP静态资源直接返回不转发后端限流算法漏桶 / 令牌桶。3API 网关层Spring Cloud Gateway用户鉴权、token 校验接口限流全局限流、接口维度限流参数校验非法请求直接丢弃熔断降级后端压力大直接返回 “活动太火爆请稍后重试”。4应用服务层多级拦截核心过滤无效请求大部分请求在这里直接拒绝不要打到 Redis、DB时间校验未到秒杀时间直接返回用户限购校验Redis 记录用户是否已经抢到同一用户只能下 1 单库存预判断Redis 判断库存库存为 0 直接返回不往下走令牌桶削峰只放行部分请求其余直接返回火爆防重复提交防前端重复点击用 requestId 幂等。关键点不要在这里直接扣数据库库存同步扣 DB 会直接压垮 MySQL5Redis 层核心热点存储Redis 承担绝大部分读请求MySQL 只处理最终落库。 Redis 存储内容seckill:goods:{id}:stock商品剩余库存seckill:goods:{id}:user_set已经抢到商品的用户集合做限购商品基础信息缓存扣库存方案Lua 脚本保证原子性不能分开多条命令getdecr会出现并发超卖Lua 脚本保证多条命令原子执行。 Lua 脚本逻辑判断秒杀是否开启判断库存是否 0判断用户是否已经抢过库存 - 1将用户 id 加入已抢集合返回成功 / 失败标记。✅ 返回成功发送消息到 MQ ❌ 返回失败直接返回 “抢购失败”。Redis 只做预扣库存真实库存扣减、订单创建交给 MQ 异步处理。6RocketMQ/Kafka 消息队列削峰异步Redis 抢购成功后发送消息到 MQ立刻给前端返回 “排队中”不是立即返回下单成功。MQ 作用异步削峰把瞬时洪峰变成平缓流量保护 MySQL消费者消费消息执行真实业务MySQL 扣真实商品库存创建订单记录创建秒杀订单如果 DB 扣库存失败数据库真实库存不足需要回滚 Redis 库存消息可靠性消息持久化、ACK 机制、失败重试、死信队列。7MySQL 数据库层兜底MySQL 只处理最终订单与真实库存流量已经被前面 CDN‑Nginx‑Redis‑MQ 层层过滤QPS 大幅下降。 表设计核心两张表sql-- 秒杀商品表 create table seckill_goods( id bigint primary key, goods_id bigint, stock int comment 真实库存, start_time datetime, end_time datetime ); -- 秒杀订单表 create table seckill_order( id bigint primary key auto_increment, order_no varchar(64), user_id bigint, goods_id bigint, status tinyint comment 0未支付 1已支付 2已取消, create_time datetime, unique key uk_user_goods(user_id,goods_id) -- 唯一索引数据库层防止用户重复下单 );uk_user_goods唯一索引数据库兜底防用户重复下单即使上层缓存出问题数据库也不会产生重复订单。库存更新使用数据库行锁update seckill_goods set stock stock -1 where id ? and stock 0;一定要带上stock0数据库行锁保证不会超卖。订单超时取消秒杀订单一般 15 分钟未支付自动取消方案 1MQ 延迟消息创建订单发送延迟消息时间到消费回补 RedisDB 库存方案 2定时任务扫描超时订单数据量大不推荐。三、核心问题解决方案1、超卖问题重中之重超卖根源并发下库存扣减非原子。 多层防护Redis Lua 脚本原子预扣MQ 消费时 MySQL 执行update ... where stock0行锁扣库存订单表唯一索引 uk_user_goods防止同一个用户多单。2、少卖问题场景Redis 扣了库存DB 扣库存失败没有回补 Redis导致库存对不上。 处理MQ 消费 DB 操作失败回滚 Redis 库存把用户从已抢购集合移除。3、热点 key 大 Key 问题Redis秒杀商品是超级热点 key大量请求打同一个 keyCPU 打满。 优化方案本地缓存Caffeine应用内存缓存商品基础信息减少到 Redis 网络请求库存不能本地缓存库存必须走 RedisRedis 热点 key 分片一个商品拆成多个库存 key分散请求压力Redis 集群避免单节点压力过大。4、高可用保障Redis 主从 哨兵 / Cluster 集群避免单点MQ 集群多 brokerMySQL 主从读写分离秒杀写走主库服务多实例部署K8s 水平扩容降级熔断高峰期关闭非核心功能直接返回 “活动火爆”。5、防黄牛验证码秒杀前需要滑动验证码打散请求时间避免请求同一时刻涌入用户 token 校验不能裸接口请求IP 限流、账号黑名单禁止直接暴露秒杀接口需要拿到令牌才允许进入抢购逻辑。四、完整业务执行流程用户访问秒杀页面 → CDN 返回静态页面到秒杀时间前端获取抢购令牌请求打到 Nginx、网关经过 IP 限流、鉴权应用层做时间校验、本地限购快速判断执行 Redis Lua 脚本校验时间、库存、用户是否已抢Lua 返回成功发送消息到 MQ前端返回【排队中请等待结果】MQ 消费者消费消息MySQL 执行扣库存创建秒杀订单数据库失败 → 回补 Redis 库存前端轮询 /websocket 查询订单状态用户 15 分钟未支付延迟消息触发订单关闭库存回补。五、性能指标三高目标高性能单接口 RT 50ms绝大部分请求在网关、Redis 拦截DB QPS 可控高并发单机应用支持上万 QPS集群支撑十万 QPS高可用任意中间件节点故障不导致整体不可用熔断降级保障核心流程可用。六、可选优化进阶预加载秒杀开始前提前把商品库存加载进 Redis流量预热验证码打散瞬时峰值读写分离商品查询走从库订单写入走主库分布式锁这里不推荐 Redisson 锁做秒杀锁会成为瓶颈优先 Lua 脚本分库分表订单量大时seckill_order 做分表七、面试高频坑点总结❌ 不能直接请求 DB 扣库存会直接打崩数据库❌ 不要 Redis 先 get再 decr分开命令会超卖必须 Lua❌ Redis 扣成功不代表下单成功DB 仍可能失败必须处理回滚✔ 多层防护缓存层、MQ、数据库三层共同保证库存正确性✔ 抢购成功不等于下单成功前端不能直接提示成功需要异步轮询结果。