技术实践

一次 10 万 QPS 秒杀的容量规划复盘

优贸科技研究院 · 交易平台团队 3 分钟阅读
一次 10 万 QPS 秒杀的容量规划复盘 — 微服务中台架构与服务器基础设施
技术实践

从容量估算、链路瓶颈定位到降级预案,记录一次大促保障的完整过程,以及三个事后才想明白的教训。

从业务目标反推技术指标

大促保障的第一步不是压测,是把业务目标翻译成技术指标

客户给出的目标是:活动开始后 1 分钟内完成 30 万单。基于历史数据,我们做了如下推导:

  • 下单成功 30 万单,按 3:1 的浏览下单比,需要承接约 90 万次商品详情请求;
  • 秒杀流量高度集中,实测约 60% 的请求落在前 10 秒;
  • 峰值 QPS ≈ 90 万 × 60% ÷ 10 ≈ 5.4 万
  • 考虑重复点击与前端重试,按 2 倍冗余设计,目标 10 万 QPS

这个推导过程的价值在于:它让每一个技术指标都有业务依据,而不是拍脑袋定一个"看起来够大"的数字。

分层削减:让请求尽早结束

10 万 QPS 全部打到数据库是不现实的。我们的策略是分层拦截,让请求在尽可能靠前的位置结束。

CDN 层:静态资源、商品图片、活动页面全部走 CDN,这部分请求根本不进机房。

网关层:按用户维度限流,同一用户 1 秒内超过 3 次请求直接拒绝。这一层拦掉了大量的重复点击。

应用层:商品详情、库存余量走本地缓存 + Redis 二级缓存,缓存命中率目标 99% 以上。库存余量允许有 1–2 秒延迟,用户看到的"剩余数量"不必绝对精确。

数据库层:只有真正的下单请求会落库,通过前面三层削减后,实际到达数据库的 QPS 控制在 3000 以内。

库存扣减的热点问题

前面提到的分桶方案就是在这个项目中打磨出来的。核心思路是把单个 SKU 的库存拆成 N 个逻辑桶,请求按用户 ID 哈希路由,将单行锁竞争分散到 N 行。

需要注意两个细节:

桶数量不是越多越好。 桶太多会导致某些桶提前售罄而其他桶还有余量,用户体验上表现为"明明显示有货却下单失败"。我们的经验值是按预估并发的 1/500 设桶,并实现桶间借调。

借调要有次数上限。 无限制借调会在库存接近售罄时引发雪崩式的跨桶查询。设置最多借调 2 次,失败即返回售罄。

降级预案:想清楚可以放弃什么

预案的本质是提前决定在资源不足时牺牲什么。我们准备了三级:

一级(黄色):关闭商品推荐、评价列表、销量排行等非核心模块。

二级(橙色):订单列表、物流查询等查询类功能限流,优先保障下单链路。

三级(红色):开启排队页,超出承载能力的用户进入等待队列,宁可让部分用户等待,也不能让全部用户失败。

关键在于这些开关必须在压测中实际演练过。没演练过的预案,在真实故障时没人敢按。

三个事后才想明白的教训

第一,压测环境的数据分布要和生产一致。 我们最初用均匀分布的测试数据压测,结果非常漂亮。真实流量下却出现了性能骤降——因为真实场景中 80% 的请求集中在 3 个爆款 SKU 上,热点程度完全不同。后来我们用生产流量回放重新压测,才暴露出真实瓶颈。

第二,别忘了下游系统。 交易链路扛住了,但订单同步到 ERP 的任务积压了 40 分钟。ERP 是第三方系统,扩容不在我们控制范围内。最终的解法是在集成层加了缓冲队列并做了削峰,这个环节在最初的容量规划中被完全遗漏了。

第三,监控要按业务维度看。 系统监控显示一切正常(CPU 60%、错误率 0.1%),但客服反馈某个渠道的用户大量下单失败。原因是那 0.1% 的错误全部集中在一个渠道上。此后我们把核心指标全部按渠道、按商品类目拆分展示,平均值会掩盖问题。

结语

大促保障是一项系统工程,技术方案只占一半,另一半是演练、预案与协同机制。真正决定成败的,往往是那些在压测报告里看不到的细节。

全部文章

这篇文章对你有启发吗?

如果文中的判断正好戳中你正在面对的问题,欢迎带着具体场景来找我们,我们可以聊得更深。

预约咨询 查看行业案例 联系我们 企业微信联系二维码 微信扫一扫,添加企业微信