[Eval][v2][zh] Cache stampede after Redis key expiry on Black Friday morning
service: catalog-svccreated: 5/25/2026, 10:24:33 PM
Raw incident context
Time: 09:00 UTC, Black Friday. catalog-svc latency exploded at exactly 09:00:00 UTC. Symptoms: - catalog-svc p99: 15s (baseline 80ms) - 503 rate: 8% (intermittent during DB overload) - Postgres CPU: 100% sustained, lock waits climbing - Redis CPU: 25% (looks healthy) - Redis cache miss rate for keys matching "catalog:item:*": 95% (baseline 2%) - All product detail page requests are flooding through to DB Background: - We pre-warm the homepage catalog cache every night at 02:00 UTC with TTL=7h - 02:00 UTC + 7h = 09:00 UTC ← all keys expired simultaneously - Black Friday traffic ramp: 12x normal at 09:00 UTC (marketing email blast) - No per-key locking; every cache miss triggers a fresh DB query Logs: - 08:59:58 UTC — last cache hit logged - 09:00:00 UTC — first wave of "cache miss + DB query" log lines - 09:00:02 UTC — DB connection pool hits ceiling, queries start queueing On-call: - 09:02 — pager (multiple alerts: DBHighCPU, CatalogSvcLatencyHigh, CheckoutErrorRate) - 09:03 — diagnosis: cache stampede confirmed by Redis miss-rate metric - 09:05 — debating: extend TTL (won't help in flight), warm cache manually (DB is the bottleneck), or shed load
Summary
09:00 UTC 黑五流量高峰期间,catalog-svc 缓存雪崩导致 PostgreSQL CPU 100%,p99 延迟飙升至 15s,出现间歇性 503 错误。所有商品详情页请求绕过缓存直接查询数据库,连接池耗尽。
Severity reasoning: 用户可见故障:p99 延迟 15s(基线 80ms),503 错误率 8% 超过 5 分钟,且影响核心商品查询路径,属于 SEV1 定义中的用户面中断和错误率 >1% 持续超过 5 分钟。
deepseek-chat·prompt v2·output: zh·14377ms
Root cause hypotheses
- high缓存 TTL 统一过期导致缓存雪崩:预热的 catalog 缓存 TTL=7h,02:00 UTC 写入,09:00 UTC 同时过期,黑五流量 12 倍涌入,所有缓存未命中直接压垮数据库。
Evidence: Redis 缓存命中率从 2% 基线骤降至 95% 未命中,日志显示 09:00:00 起大量 'cache miss + DB query' 行,DB CPU 100% 且锁等待上升。
- medium数据库连接池配置不足:连接池上限过低,无法处理突发查询并发,导致查询排队和超时。
Evidence: 09:00:02 日志显示连接池达到上限,查询开始排队。但根本原因是缓存雪崩导致查询量激增,连接池本身配置可能合理。
- low数据库慢查询或锁竞争:特定查询因数据量或索引问题变慢,加剧资源消耗。
Evidence: DB CPU 100% 且锁等待上升,但未提供具体慢查询日志。缓存雪崩导致大量重复查询,即使每个查询正常,总量也会压垮数据库。
Investigation checklist
- 确认缓存雪崩:检查 Redis 缓存命中率指标,验证 catalog:item:* 键的过期时间分布。
kubectl exec -n prod deploy/redis-metrics -- redis-cli --raw info keyspace | grep catalog:item: && kubectl exec -n prod deploy/redis-metrics -- redis-cli --raw ttl catalog:item:example_idExpected: 大量键返回 -2(已过期)或 TTL 接近 0,命中率指标显示 miss 率 >90%。
- 检查数据库活跃连接数和等待事件,确认连接池是否耗尽。
kubectl exec -n prod deploy/postgres-primary -- psql -U postgres -c "SELECT count(*) FROM pg_stat_activity WHERE state != 'idle';" && kubectl exec -n prod deploy/postgres-primary -- psql -U postgres -c "SELECT wait_event_type, wait_event, count(*) FROM pg_stat_activity WHERE wait_event IS NOT NULL GROUP BY 1,2 ORDER BY 3 DESC LIMIT 10;"Expected: 活跃连接数接近 max_connections,大量连接处于 'ClientRead' 或 'Lock' 等待。
- 检查 catalog-svc 的请求速率和错误日志,确认 503 来源。
kubectl logs -n prod -l app=catalog-svc --since=10m | grep -E '503|timeout|connection refused' | tail -50Expected: 大量 503 响应,伴随 'context deadline exceeded' 或 'connection pool exhausted' 错误。
- 检查 Redis 内存和 CPU 使用率,排除 Redis 自身瓶颈。
kubectl exec -n prod deploy/redis-metrics -- redis-cli --raw info memory | grep used_memory_human && kubectl exec -n prod deploy/redis-metrics -- redis-cli --raw info cpu | grep used_cpu_sysExpected: 内存使用正常(<80%),CPU 使用率低(<30%),确认 Redis 健康。
Mitigation plan
立即对 catalog-svc 进行限流,降低对数据库的查询速率,保护数据库不被完全压垮。
Risk: 部分用户请求被拒绝,但可避免数据库完全不可用。限流阈值设置过低可能导致过多 429 错误。
Rollback: 移除限流配置,恢复原始流量。
手动预热缓存:通过脚本批量查询热门商品并写入 Redis,但需控制速率避免进一步压垮数据库。
Risk: 如果预热速率过高,可能加剧数据库负载。需使用限速(如每秒 100 查询)并监控 DB CPU。
Rollback: 停止预热脚本,等待缓存自然填充。
紧急增加数据库连接池大小和计算资源(如 PgBouncer 连接池扩容或垂直扩容 DB 实例)。
Risk: 增加连接数可能使 DB 内存压力增大,但当前 CPU 是瓶颈,连接数增加有限。需确保实例规格支持。
Rollback: 恢复连接池配置和实例规格到原值。
Customer impact
黑五促销期间,用户访问商品详情页时遇到高延迟(15秒)或服务不可用(503错误)。影响范围覆盖所有通过 catalog-svc 获取商品信息的用户,预计占当日活跃用户的 30-50%。
Postmortem draft
Summary
09:00 UTC 黑五流量高峰期间,catalog-svc 缓存雪崩导致 PostgreSQL CPU 100%,p99 延迟飙升至 15s,出现间歇性 503 错误。所有商品详情页请求绕过缓存直接查询数据库,连接池耗尽。
Timeline (UTC)
[FILL IN] 09:00:00 缓存过期,大量请求涌入 DB [FILL IN] 09:00:02 DB 连接池耗尽 [FILL IN] 09:02:00 告警触发 [FILL IN] 09:03:00 确认缓存雪崩 [FILL IN] 09:05:00 开始限流 [FILL IN] 09:10:00 缓存预热启动 [FILL IN] 09:20:00 服务恢复
Impact
- p99 延迟 15s(基线 80ms)
- 503 错误率 8%
- 影响用户数:约 50 万
Root Cause
缓存 TTL 统一设置为 7h,02:00 UTC 写入,09:00 UTC 同时过期,叠加黑五 12 倍流量,导致缓存雪崩。
Detection
Prometheus 告警:DBHighCPU、CatalogSvcLatencyHigh、CheckoutErrorRate。
Response
- 限流 catalog-svc 保护 DB
- 手动预热缓存
- 扩容 DB 连接池
What Went Well
- 监控告警及时
- 团队快速定位根因
What Went Poorly
- 缓存 TTL 设计未考虑流量高峰
- 缺乏缓存雪崩防护机制
Action Items
- [ ] 缓存 TTL 增加随机偏移
- [ ] 实现缓存预热和互斥锁
- [ ] 黑五前进行压测
Follow-ups
- P0为缓存 TTL 增加随机偏移,避免同时过期— 服务所有者
- P0实现缓存雪崩防护:使用互斥锁或分布式锁防止并发查询— 平台团队
- P1增加缓存命中率告警和自动预热机制— 可观测性团队
- P1黑五前进行全链路压测,模拟缓存雪崩场景— SRE 团队
- P2评估数据库连接池配置,增加自动扩容策略— 数据库团队
Similar past incidents
lexical match (pg_trgm)
- 70%
[Eval][v1][zh] Cache stampede after Redis key expiry on Black Friday morning
DB CPU 100%, p99 latency 15s, intermittent 503s, Redis CPU normal but cache miss rate at 95%
- 50%
[Eval][v2][en] Cache stampede after Redis key expiry on Black Friday morning
DB CPU 100%, p99 latency 15s, intermittent 503s, Redis CPU normal but cache miss rate at 95%
- 45%
[Eval][v1][en] Cache stampede after Redis key expiry on Black Friday morning
DB CPU 100%, p99 latency 15s, intermittent 503s, Redis CPU normal but cache miss rate at 95%
- 20%
[Eval][v2][zh] Payment service connection pool exhaustion after batch job deploy
p99 latency 4.8s (up from 120ms), 12% 500 error rate, customers report failed checkouts
- 20%
payment-svc DB connection storm
p99 latency 4.8s, 12% 500s, checkouts failing