连载中 1/20

爆单那天:雪崩是怎么发生的

2026-07-06 · 3515 阅读 · 0 评论 · 0 赞

十点整,流量像开了闸

老王给 503 咖啡馆三周年策划了「半价日」活动,会员群里预热了三天。10 点整活动上线,App 弹窗推送齐发——一分钟内,下单接口的流量冲到平时的四十倍。监控大盘从绿变黄只用了二十秒,从黄变红又用了二十秒,第三分钟,全站 502,连商品详情页都打不开了。用户投诉像雪片,老王给我打电话时系统还在反复重启反复倒下。这本系列就从这条灾难链讲起——雪崩不是一瞬间的意外,是一条有先后顺序的因果链,每一环都能在代码里找到根源。

第一幕:慢——从连接池打满开始

灾难的第一环在数据库。秒杀下单的接口里有一个热点查询:查库存,走的是一张大表的行级更新,平时 RT(响应时间)50 毫秒。流量冲高四十倍后,数据库 CPU 先顶到 100%,查询排队,RT 从 50 毫秒爬到 500 毫秒、再爬到 5 秒。容量是按「平时流量 × 安全余量」规划的,四十倍流量下,每一个环节都在超卖。应用这头,每个请求都要占一个数据库连接,查询从 50 毫秒变成 5 秒,连接的持有时间翻了一百倍——连接池的 50 个连接瞬间被占满,第 51 个请求开始排队等连接,队伍越排越长。

第二幕:堆积——线程池的连锁窒息

连接池满了,请求在等连接;等连接的是谁?是 Tomcat 的工作线程。每个 HTTP 请求占一个工作线程,线程在数据库查询上阻塞 5 秒,200 个工作线程在 10 秒内全部阻塞在等连接或等查询上。新请求到达时没有线程接待,进入 Tomcat 的等待队列;队列满了,操作系统层面直接拒绝连接。此时用户看到的现象是:下单接口超时,商品详情接口也超时——它们明明是两个接口、两张表,但它们共享同一个 Tomcat 线程池、同一个数据库连接池,这就是连坐的物理基础。

第三幕:连坐——不相关的服务陪葬

更糟的还在后面。订单服务挂了,但用户手机上的 App 不会因此停手:购物车刷不出来会刷新,详情页打不开会重试,失败触发重试,重试变成新的流量,洪峰之上再叠一层洪峰。会员服务调用订单服务查「最近订单」,没有超时设置,默认等到天荒地老——会员服务的线程也全阻塞了。网关后面一排服务,一个倒下,传染一片,这就是雪崩这个词的本义:一块雪松动,整面山坡跟着滑。分布式锁系列第 19 篇的事故五(高频抢锁拖垮注册中心)是这条链的特例,本系列要把整条链系统性拆掉。

第四幕:重启风暴

运维的直觉反应是重启。服务重启要 30 秒,这 30 秒里积压的请求、重试的请求、心急的用户多点几次的请求,全在门外候着——服务刚一起来,积压的流量一齐涌入,刚扩的连接池刚热身就被打满,30 秒后再次倒下。重启一次,倒下一次,系统在死亡边缘反复震荡。老王的半价日最后以「临时下线活动」收场,优惠券没发完,客诉发了一周。

时间现象根因
10:00-10:00:20下单 RT 从 50ms 爬升DB 容量超卖,热点查询排队
10:00:20-10:01连接池满,请求排队RT 拉长导致连接持有时间暴涨
10:01-10:02线程池阻塞,全接口超时共享线程池,无隔离无超时
10:02-10:03不相关服务连坐,全站 502重试风暴 + 无熔断,故障传染
10:03 之后重启后立刻再倒积压流量冲击,无预热无限流

四板斧与一块地基

复盘这条灾难链,每一幕都对应一味药:限流——流量超过容量就果断少接点,宁可得罪十个用户,不能拖垮全站(第 2 到 9 篇);熔断——下游病了就别再问它,快速失败防止线程被拖死(第 10 到 12 篇);降级——接不住的请求给个体面的兜底,而不是裸超时(第 13 篇);隔离——把资源切成舱壁,一舱进水不沉全船(第 14 篇)。这四板斧全都站在同一块地基上:超时——没有超时,任何保护机制都会被「永远等下去」的线程架空(第 15 篇)。下一篇从四板斧的第一把讲起:限流的第一课,固定窗口计数器——最朴素的算法,最经典的突刺。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#雪崩#过载#连接池#线程池#重试风暴#连坐

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞