理解 Thundering Herd Problem:在分布式系统中驯服冲锋
Source: Dev.to
惊群问题
想象一家热门商店在 上午 9 点准时 开门。数百名顾客在门外排队,随后同时冲进去,导致收银员不堪重负,现场一片混乱。
在分布式系统中,当 大量请求同时涌向同一个共享资源 时,也会出现同样的情况——这就是 惊群问题(Thundering Herd Problem)。
Diagram
NORMAL OPERATION (Cache Hit) THUNDERING HERD (Cache Miss Stampede)
Fast path Failure path
┌─────────────┐ ┌─────────────┐
│ Clients │ │ Clients │
│ 10k users │ │ 10k users │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌─────▼─────┐ Cache Hit ┌──────────────┐ ▼
│ App Server│◄──────────────│ Redis Cache │ ┌──────▼──────┐
│ Node 1 │ │ key=product1 │ │ 10k Cache │
└─────┬─────┘ │ TTL=60s │ │ MISSES │
│ └──────┬───────┘ └──────┬──────┘
│ Cache Miss │ │
▼ ▼ ▼
┌─────▼─────┐ ┌──────────────┐ ┌──────────────┐
│ App Server│ │ Database │ │ Database │
│ Node 2 │◄─── 1 Query ────│ 1 Query Only │ │ 10k Queries! │
└─────┬─────┘ │ Returns Data│ │ CPU=1000% │
│ └──────┬───────┘ └──────────────┘
│ │ 💥 OVERLOAD
└──────────┬─────────────────┘
│
┌────▼────┐
│Cache Set│ ← Serves all 10k clients
└─────────┘
什么是 Thundering Herd Problem?
The Thundering Herd Problem occurs when numerous clients or processes simultaneously compete for the same shared resource (e.g., a database or cache). This creates a sudden traffic spike that overwhelms the system. Unlike a gradual load increase, the herd is synchronized burst—think of cache keys expiring at the exact same timestamp across millions of requests.
Source: …
常见出现位置
| 组件 | 典型场景 |
|---|---|
| 缓存系统 | 常见的缓存条目同时失效,导致大量后端请求一次性触发。 |
| 数据库 | 多个应用服务器在缓存未命中后同时冲击数据库。 |
| 负载均衡器 | 故障发生时,请求涌向唯一健康的节点。 |
| 锁获取 | 进程在关键区争抢互斥锁。 |
在典型的应用架构中:
- 客户端向应用服务器发起查询。
- 服务器首先检查 Redis(或其他缓存)。
- 缓存命中? 立即返回。
- 缓存未命中? 从数据库读取,重新填充缓存,然后返回。
实际案例:缓存过期突发
考虑 Netflix 推出一部热门新剧。数百万用户请求已缓存、TTL 为 60 秒 的剧集数据。当 TTL 失效时:
Normal: Cache serves 10k req/s at ~1 ms latency
Expiry: 10k DB queries at ~100 ms each → 5‑10× overload
结果:数据库连接耗尽,延迟飙升至秒级,级联故障影响整个应用。类似的突发在印度 IPL 票务销售或黑色星期五电商抢购时也会出现。

正常流量激增 vs. 雷鸣羊群
| 方面 | 正常流量激增 | 雷鸣羊群 |
|---|---|---|
| 原因 | 自然增长(营销、活动) | 同步事件(TTL 过期、定时任务) |
| 模式 | 逐步上升 | 瞬时突发 |
| 影响 | 自动伸缩能够应对 | 即使扩容也会被压垮 |
| 持续时间 | 分钟‑小时 | 秒级(但破坏性极大) |
| 关键区别 | 可预测,分散 | 可预测 但 同步化,将极小的脆弱窗口放大为故障 |
为什么在分布式系统中它是危险的
Clients → App → DB overload → Timeouts → Retries → More DB load → 💥
- 放大效应 – 1 次缓存未命中 → N 次数据库查询(其中 N = 并发客户端数)。
- 尾部延迟 – 最慢的数据库查询会阻塞所有请求。
- 级联故障 – 过载的数据库导致应用变慢 → 更多超时 → 重试风暴。
- 自动扩容滞后 – 突发流量持续时间太短,无法让新实例及时启动。
- 在多区域部署中,一个区域的抢占式请求会在全球范围内产生连锁反应。
系统影响细分
CPU 过载
- 突然的线程爆炸冲击调度器;上下文切换激增。
数据库压力
- 连接池耗尽;查询队列膨胀 → 超时连锁。
缓存失效
- 在流量冲击期间变得毫无用处——甚至比根本没有缓存更糟!
延迟爆炸
- P99 延迟可能飙升 100 倍,导致用户放弃会话。
防护技术
- Stale‑While‑Revalidating – 只有一个请求刷新缓存;其他请求返回陈旧数据并复用结果。
- Mutex (Distributed Lock) – 使用锁(例如 Redis
SETNX)确保只有一个请求访问数据库。 - Jitter on TTL –
TTL = base + random(0, maxJitter),避免同步失效。 - Probabilistic Early Computation – 根据访问频率或接近失效时间提前刷新热点键。
- Rate Limiting – 限制每个键/用户的请求次数,防止后端过载。
- Circuit Breaker / Bulkhead – 隔离故障组件并在羊群效应传播前削减负载。
- Cache Warm‑up – 在关键键过期前预先填充(例如在低流量时段)。
缓存预热
- 在流量激增或部署前预加载热点键。
真实故障案例:Facebook 2010 年的缓存踩踏导致数小时才能恢复——
The Day Facebook Died – A Cache‑Stampede Horror Story That Changed Tech Forever
最后思考
惊群效应(Thundering Herd)把“大规模工作”变成没有适当防护的宕机。
掌握这些模式——错峰 TTL + 合并 + 退避。
下次缓存过期时,请记住:单只牛还行,成群的牛致命。