[Eval][v3][zh] Cache stampede after Redis key expiry on Black Friday morning
service: catalog-svccreated: 6/2/2026, 11:42:26 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 Black Friday期间,catalog-svc因缓存雪崩导致数据库CPU 100%,p99延迟飙升至15秒,8%请求返回503。所有产品详情页请求绕过Redis直接查询Postgres,连接池耗尽。
Severity reasoning: 用户可见故障:p99延迟15秒(基线80ms),503错误率8%>1%且持续超过5分钟,收入路径(产品详情页)中断,符合SEV1标准。
deepseek-chat·prompt v3·output: zh·14061ms·2467↑ / 2027↓ tok·$0.00290
Root cause hypotheses
- high缓存雪崩:所有catalog:item:*键在09:00 UTC同时过期,TTL=7h,预缓存时间为02:00 UTC。
Evidence: Redis缓存未命中率从2%飙升至95%,日志显示08:59:58最后一次命中,09:00:00开始大量缓存未命中+DB查询。
- high数据库连接池耗尽:大量并发查询导致连接池满,查询排队。
Evidence: Postgres CPU 100%,锁等待增加,连接池达到上限后查询开始排队。
- highBlack Friday流量激增:营销邮件导致流量为正常12倍,加剧了缓存雪崩的影响。
Evidence: 上下文提到Black Friday流量12倍于正常,且09:00 UTC为邮件发送时间。
- high缺少缓存逐出保护机制:没有每键锁定或增量缓存重建,导致所有并发请求同时回源。
Evidence: 上下文明确说明无每键锁定,每个缓存未命中都触发DB查询。
- medium数据库查询效率低下:产品详情页查询可能未优化,导致高负载下CPU饱和。
Evidence: Postgres CPU 100%,但未提供具体查询分析,可能性中等。
Investigation checklist
- 确认缓存雪崩:检查Redis缓存未命中率趋势
redis-cli -h redis-cache -p 6379 INFO stats | grep keyspace_missesExpected: keyspace_misses_hits_ratio显示未命中率>90%
- 检查数据库活跃连接数和等待事件
SELECT count(*) FROM pg_stat_activity WHERE state = 'active'; SELECT wait_event_type, count(*) FROM pg_stat_activity WHERE state = 'active' GROUP BY wait_event_type;Expected: 活跃连接数接近池大小,等待事件多为'Client'或'Lock'
- 查看当前运行最慢的查询
SELECT pid, now() - pg_stat_activity.query_start AS duration, query, state FROM pg_stat_activity WHERE state != 'idle' ORDER BY duration DESC LIMIT 10;Expected: 多个查询持续时间超过10秒,且为catalog-svc的SELECT语句
- 检查Redis键过期情况
redis-cli -h redis-cache -p 6379 --bigkeys | grep 'catalog:item'Expected: 大量键在09:00左右过期,TTL为0
- 验证缓存预热时间与TTL
kubectl logs -n prod -l app=catalog-svc --since=24h | grep 'cache warm' | tail -5Expected: 显示预热在02:00 UTC完成,TTL设置为7h
Mitigation plan
立即启用缓存逐出保护:在应用层实现每键锁定(如SETNX),防止并发回源。
Risk: 需要代码变更,无法快速部署;若锁定实现不当可能导致死锁。
Rollback: 回滚代码变更,恢复原有逻辑。
手动预热缓存:通过脚本批量查询热门商品,填充Redis缓存。注意:DB已过载,需限制并发。
Risk: 可能进一步压垮数据库,导致完全不可用。
Rollback: 停止预热脚本,等待DB恢复。
临时增加数据库连接池大小(如从50增至100),并启用查询排队。
Risk: 增加DB负载,可能加剧CPU使用率。
Rollback: 恢复连接池原值。
对catalog-svc实施限流,丢弃部分请求以保护数据库。
Risk: 用户看到更多503错误,但可防止完全崩溃。
Rollback: 移除限流规则。
扩展catalog-svc副本数,分散负载。
Risk: 增加副本可能增加DB连接数,需同步调整连接池。
Rollback: 缩容副本数。
Customer impact
用户访问产品详情页时遇到严重延迟(页面加载超过15秒)或间歇性错误(503),影响所有通过catalog-svc浏览商品的用户。Black Friday期间流量高峰加剧了问题。预计恢复时间待定。
Postmortem draft
事后复盘
摘要
09:00 UTC,Black Friday期间,catalog-svc因缓存雪崩导致数据库过载,p99延迟15秒,503错误率8%。
时间线(UTC)
- 02:00 - 缓存预热完成,TTL=7h
- 08:59:58 - 最后一次缓存命中
- 09:00:00 - 缓存雪崩开始,大量DB查询
- 09:00:02 - DB连接池耗尽
- 09:02 - 告警触发
- 09:03 - 诊断确认缓存雪崩
- [FILL IN] - 缓解措施实施
- [FILL IN] - 服务恢复
影响
- p99延迟从80ms升至15s
- 503错误率8%
- 影响所有产品详情页请求
- 估计受影响用户数:[FILL IN]
根因
- 缓存键同时过期(TTL=7h,预热时间02:00 UTC)
- 无每键锁定,所有并发请求回源DB
- Black Friday流量12倍于正常
检测
- 告警:DBHighCPU、CatalogSvcLatencyHigh、CheckoutErrorRate
- 检测延迟:2分钟(从发生到告警)
响应
- 09:02 收到告警
- 09:03 诊断缓存雪崩
- 讨论方案:延长TTL(无效)、手动预热(风险高)、限流
做得好的
- 告警配置完善,快速定位
- Redis指标清晰显示缓存未命中率
做得不好的
- 缓存策略未考虑雪崩防护
- 无每键锁定机制
- 未对Black Friday流量进行压测
行动项
- [FILL IN] 实现缓存逐出保护(每键锁定)
- [FILL IN] 缓存预热增加随机TTL偏移
- [FILL IN] 对catalog-svc进行负载测试
- [FILL IN] 增加缓存监控告警(未命中率阈值)
Follow-ups
- P0实现缓存逐出保护:在catalog-svc中添加每键锁定(如Redis SETNX),防止并发回源。— catalog-svc 开发团队
- P0优化缓存预热策略:增加随机TTL偏移(如±30分钟),避免同时过期。— catalog-svc 开发团队
- P1对catalog-svc进行Black Friday级别的负载测试,验证缓存雪崩场景。— 性能测试团队
- P1增加缓存未命中率告警,阈值设为>50%持续1分钟。— 可观测性团队
- P2评估数据库连接池大小和查询性能,优化慢查询。— DBA团队
- P1制定缓存雪崩应急手册,包括手动预热脚本和限流步骤。— on-call SRE
Similar past incidents
lexical match (pg_trgm)
- 71%
[Eval][v2][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%
- 63%
[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%
- 46%
[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%
- 18%
[Eval][v2][en] Payment service connection pool exhaustion after batch job deploy
p99 latency 4.8s (up from 120ms), 12% 500 error rate, customers report failed checkouts