之前的文章中我们已经演练了缓存的三种"招式":用读缓存化解数据库查询压力,靠写缓存扛住流量洪峰,再通过消息队列从容同步数据。这套组合拳------先缓冲、再异步、平稳落库------正是接下来面对真刀真枪的秒杀场景时,我们要继续运用的核心战术。
1 业务场景:设计秒杀架构必知必会的那些事
想象这样一个场面:某天,公司决定拿出100件"骨折价"商品,在10月10日晚上10点10分准时开抢。而这时候,平台已经坐拥几千万用户,哪怕只吸引来几十万想捡便宜的,也意味着 ------ 开抢那一两秒,流量会像演唱会放票般瞬间冲顶,之后秒光,只剩"已售罄"的页面迎接后来者。
更"刺激"的是,领导发话:这是个临时活动,服务器不能大动,架构别大改,要求我们"精打细算"地接住这股洪流,别让系统被冲垮。
所以问题来了:如何用最小代价,设计一套秒杀架构?
核心原则其实就这四条,咱们得牢牢守住:
- 货不能多卖 ------说好100件就100件;
- 订单不能丢 ------抢成功的必须算数;
- 系统不能挂 ------服务器和数据库得稳住;
- 尽量防住机器人 ------把货留给真人用户。
那具体怎么实现?咱们接下来就聊聊整体设计思路。
2 整体思路
秒杀架构的本质,就像一个精心设计的"流量漏斗"------它的核心策略是层层设卡,逐级过滤 ,让越多的请求在上游就被消化或拦截,尽量不让压力渗透到系统底层。
如下图从架构分层的视角 看,我们的目标很明确:把请求尽可能拦在上游,别放它往下游冲 。系统越靠下游,往往越脆弱、越昂贵,保护数据库和核心服务是重中之重。

那具体怎么拦?不能光靠想象。因为秒杀本身是一连串用户操作(浏览、点击、下单、支付...),所以必须结合完整的业务流程来设计拦截点 。每一个用户动作,都是一个可能设防的关卡。下图更直观地展现这个"何处设卡、如何引导"的过程,

接下来就按照秒杀系统的业务流程,来一步步讲解如何将请求拦截在系统上游。
2.1 浏览页面如何将请求拦截在上游
踩过坑才懂,设计秒杀时就算算力绰绰有余,也千万别忽略一个隐形杀手------带宽。我们曾有一个活动,上线后监控一切正常,唯独出口带宽被瞬间占满,结果页面卡成"PPT",用户体验一落千丈。
吃一堑长一智,从那之后我们学乖了:所有静态资源一律走 CDN,PC 网站也必须做前后端分离。简单来说,CDN 就是把你的图片、样式等文件缓存到全国各地的节点服务器上,用户访问时,由 CDN 智能调度到最近的节点返回资源,又快又省自家服务器的流量和带宽。
这样一来,静态请求的压力基本被挡在系统之外。那么动态请求怎么处理?这里有三种常见思路:
- 动态数据静态化
比如商品详情、评论等,可通过 JavaScript 动态获取。更好做法是:直接生成静态页面推送到 CDN;如果改造量大,至少放进 Redis。个人更倾向走 CDN,彻底分离压力。 - 秒杀时间判断轻量化
页面上通过 JS 获取服务器时间来控制"立即抢购"按钮的可用状态。这个"获取时间"的请求完全可以放在负载均衡或静态资源层处理,不必进入业务后台。 - 结束标识前置校验
在 Cookie 或前端存储中记录秒杀是否结束。如果未结束,请求才会进入后台,后台再依次检查本地内存 → 缓存,确认活动状态。这样可以避免无效请求。
总结一下原则 :
用户浏览类行为,尽量在 CDN、静态服务或负载均衡层完成拦截;实在不行,也必须在缓存层解决,绝不轻易放行到下游数据库。
2.2 下单页面如何将请求拦截在上游
好,我们直击秒杀最核心的战场------下单与提交 。这里的设计,直接决定系统是平稳着陆还是瞬间崩塌。
第一关:下单页面的"防刷"策略
为了防止"黄牛"或爬虫直接刷爆下单页,我们设下两道防线:
- 动态URL,绝不提前暴露
活动开始前,下单页面的真实地址是"机密"。页面只在秒杀开启瞬间,由前端JS向后台动态获取。想提前刷?门儿都没有。前面介绍了JS可以用来判断秒杀开始时间,秒杀时间一到,它便可以通过另一个请求获取这个URL。 - 按钮"一击即废"
用户点击"购买"后,按钮立即变为不可用(Disable)。简单粗暴,有效防止疯狂连点给后台送"人头"。
第二关:提交订单------流量漏斗的终极过滤
页面展示可以用CDN扛,但提交订单涉及复杂逻辑与数据一致性,是整套架构的"心脏"。原则是:在请求抵达数据库前,层层设卡,能拦则拦 。
(一)网关层:第一道也是最狠的防线
目标:用最小代价,在系统最外围拦截掉95%以上的无效或恶意流量。主要三板斧:
- 用户限频 :比如同一用户每5秒只能提交一次。
- IP限频 :防止机器人集群攻击,但需谨慎避免误伤真实用户(例如同一公司出口IP)。
- 总量限流 :采用漏桶/令牌桶 等算法,严格控制每秒进入后台的请求数量。
前两种限制比较简单,在nginx上就能快速完成配置,第3种限流方式也不复杂,相关的原理在后面的
(二)后台服务器:精准处理与数据保卫战
能到达这里的请求已是"幸运儿",我们的目标转为:保证不超卖、不丢单 。
- 库存决胜在缓存
商品库存提前预热至Redis。下单时,使用 decr 进行原子性扣减 :- 扣后结果≥0:秒杀成功,进入创建订单流程。
- 扣后结果<0:秒杀失败,立即用 incr 回滚库存。
关键约定 :秒杀期间,禁止任何其他途径修改库存(如后台编辑),通过业务流程保障缓存作为"唯一真相源"。
- 订单先写缓存,异步落库
为保护数据库,订单创建后先写入Redis。用户进入"等待页面",前端轮询查询结果。后台则:- 优先查Redis订单。
- 若Redis没有,说明已异步持久化到数据库,再去库中查询并返回给用户。这套流程与"写缓存"章节思路一脉相承。
- 批量落库与库存同步
独立进程定期(如每100毫秒)将缓存中的订单批量插入数据库,并同步扣减数据库库存。实现数据最终一致性。 - 极端情况:Redis挂了怎么办?
幸亏网关层已经挡住了大部分流量,进入后台的请求不多。此时预案很简单:- 读/扣库存失败 :直接降级到数据库,在数据库中完成库存校验与扣减。
- 写订单缓存失败 :直接写入数据库,跳过批量落库环节。
系统虽性能下降,但功能依然可用,保障了基本业务。
总结一下: 秒杀提交的设计,是外围狠心限流与内部精心守护的结合。核心思想是:利用缓存扛住并发读写,通过异步化解耦压力,最终以可控的流量与数据库平稳交互。只要守住不超卖、不丢单的底线,这场战役就赢了九成。
2.3 付款页面如何将请求拦截在上游
来到付款环节,请求的洪峰早已在之前层层关卡被充分过滤。此时的重点不再是拦截,而是稳妥地完成交易闭环。
核心就两件事:
- 确保最终一致性:支付状态、库存、订单数据必须准确同步。(数据一致性具体如何实现,我们留到后续章节深入探讨。)
- 处理好订单取消 :若发生超时未支付等业务取消逻辑,务必记得将释放的库存,同时回补至数据库和 Redis。这一步是防止资源被"锁死"的关键,相当于把回收的"弹药"重新填回弹舱。
至此,秒杀流程从流量过滤到交易完结,形成一个完整且有韧性的闭环。
2.4 整体服务器架构

要构建真正扛得住秒杀的"铁桶阵",高可用设计必须贯穿每一道防线。如图上所示,从上到下,每一层都不能是单点。简单来说,你需要:
- 前置防线集群化 :静态资源服务器、网关、后台服务,统统通过负载均衡来部署,让流量"雨露均沾",任何一台实例挂掉都无缝切换。
- 核心存储分布式化 :缓存(Redis)和数据库(DB),必须采用集群模式。数据分片、主从备份、故障自动切换(Failover),一个都不能少,这是系统不垮的基石。
- 别忘了"幕后英雄"MQ :虽然前面的分层设计里它没直接出场,但服务间异步通知、流量削峰都离不开它。消息队列本身也要高可用配置------主从、分片、故障转移机制都得安排上,确保消息不丢、服务不中断。
层层设防,环环相扣,才是高可用的精髓。
3.小结
好了,关于秒杀架构的核心要点,我们已从头到尾梳理了一遍。由于很多策略在前面的"缓存实战"中已有铺垫,本章更像一次聚焦的综合应用。
为了方便你后续设计与自查,我将关键注意事项整理为一份 《秒杀系统设计Checklist》 ,供你参考:
| 流程 | 事 项 |
|---|---|
| 浏览页面 | 静态资源放CDN |
| 浏览页面 | 秒杀期间的一些动态数据请求放入静态页面 |
| 浏览页面 | 秒杀开始的时间获取依赖服务端 |
| 浏览页面 | 秒杀结束的标识放在各个地方 |
| 下单页面 | 下单URL动态后台获取 |
| 下单页面 | 购买按钮点击后置灰(Disable) 网关从3个方面过滤请求 |
| 下单页面 | 1)用户访问频率 2)IP访问频率 3)整体流量控制 |
| 下单页面 | 库存放在Redis 中,在每次下单操作中判断其是否为0,以防止超卖 |
| 下单页面 | 订单先入缓存再批量落库 |
| 付款页面 | 订单取消时记得将商品量加回数据库和Redis 中的库存 |
| 服务器架构 | 静态资源服务器负载均衡 |
| 服务器架构 | 网关负载均衡 |
| 服务器架构 | 后台服务器负载均衡 |
| 服务器架构 | Redis 集群 |
| 服务器架构 | MQ集群 |
| 服务器架构 | 数据库集群 |
此外,还有三个重要话题我们将在后续章节展开:
- 服务雪崩防护 ------万一某个服务挂掉,如何避免连锁反应?(后续讲熔断的时候详细讲解)
- 网关限流实战 ------具体如何配置与实现?
- 支付数据一致性 ------怎样确保交易闭环严谨可靠?
这三点每一点都需要细致考虑,将在后续文章中详细讲解。
这次架构上线后,我们通过多方监控与数据核对,验证了库存与订单完全匹配,系统运行平稳。这与此前一段"血泪史"形成鲜明对比 :早期我们曾设计"保证前100名下单成功"的方案,不做限流,结果后台压力巨大且体验不公------毕竟网速和手速并非公平竞技,普通用户很难拼过"专业选手"。如今通用做法是在网关层做科学限流 ,让系统在可控压力下随机公平处理请求。有些方案在前端JS随机丢弃请求,虽也算"限流",但属于不可靠的"小聪明",应尽量避免。
秒杀场景至此告一段落。接下来,我们将进入下一部分:基于常见组件的微服务场景实战 ,从最简单的服务治理开始,由浅入深,一步步拆解微服务的核心知识与实践。