[Eval][v2][zh] Cache stampede after Redis key expiry on Black Friday morning
service: catalog-svccreated: 6/2/2026, 11:41:48 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 因缓存雪崩导致数据库 CPU 100%,p99 延迟飙升至 15 秒,间歇性 503 错误。所有商品详情页请求绕过缓存直接查询数据库,影响用户浏览和下单。
Severity reasoning: 用户可见的故障(503 错误率 8% > 1% 且持续超过 5 分钟),p99 延迟 15 秒远超基线 80ms,收入路径(商品详情页)中断,符合 SEV1 标准。
deepseek-chat·prompt v2·output: zh·12396ms·2216↑ / 1875↓ tok·$0.00266
Root cause hypotheses
- high缓存 TTL 统一设置为 7 小时,导致所有 catalog:item:* 键在 09:00 UTC 同时过期,引发缓存雪崩。
Evidence: Redis 缓存命中率从基线 2% 飙升至 95% 的 miss 率,且最后缓存命中日志在 08:59:58,09:00:00 开始出现大量缓存未命中日志。
- high黑五流量 12 倍于正常,数据库连接池耗尽,查询排队导致 CPU 100%。
Evidence: 09:00:02 日志显示连接池达到上限,查询开始排队;Postgres CPU 100% 持续。
- medium数据库查询未优化,全表扫描或缺少索引导致单个查询耗时过长。
Evidence: p99 延迟 15 秒,但基线仅 80ms,可能因大量并发查询导致锁竞争或执行计划变差。
- lowRedis 实例配置问题(如 maxmemory-policy 导致键驱逐)加剧缓存 miss。
Evidence: Redis CPU 仅 25%,但 miss 率异常高,需检查驱逐策略和内存使用。
- low应用层缓存穿透,恶意请求或爬虫绕过缓存直接请求数据库。
Evidence: 所有请求均命中缓存 miss 模式,但无特定 IP 异常流量证据。
Investigation checklist
- 确认缓存雪崩:检查 Redis 中 catalog:item:* 键的 TTL 分布
redis-cli -h <redis-host> -p 6379 --scan --pattern 'catalog:item:*' | head -100 | xargs -I {} redis-cli -h <redis-host> -p 6379 TTL {} | sort | uniq -cExpected: 大量键 TTL 为 0 或接近 0,确认同时过期
- 检查数据库当前活跃查询和锁等待
SELECT pid, query_start, state, wait_event_type, query FROM pg_stat_activity WHERE state != 'idle' ORDER BY query_start LIMIT 20;Expected: 大量查询处于 'active' 状态,wait_event_type 可能为 'Lock',查询内容为商品详情 SQL
- 检查数据库连接池使用率
SELECT count(*) FROM pg_stat_activity;Expected: 连接数接近 max_connections 配置值
- 检查 Redis 内存使用和驱逐策略
redis-cli -h <redis-host> -p 6379 INFO memory | grep -E 'used_memory|maxmemory|evicted_keys'Expected: used_memory 未接近 maxmemory,evicted_keys 为 0,排除驱逐导致 miss
- 检查应用日志中是否有异常请求模式
kubectl logs -n prod -l app=catalog-svc --since=30m | grep -iE 'cache miss|slow query' | head -50Expected: 大量 'cache miss' 日志,无特定 IP 重复请求
Mitigation plan
立即启用缓存预热:手动将热门商品数据写入 Redis,设置随机 TTL 分散过期时间
Risk: 预热过程会额外增加数据库负载,可能加剧当前问题。需控制预热并发数。
Rollback: 停止预热脚本,等待缓存自然过期或回滚代码变更
对 catalog-svc 实施限流:在网关层限制商品详情页请求速率,保护数据库
Risk: 部分用户请求被拒绝,但可防止系统完全崩溃。需设置合理阈值。
Rollback: 移除限流规则,恢复全量请求
扩展数据库读副本:将读流量临时导向只读副本,减轻主库压力
Risk: 副本可能存在复制延迟,导致数据不一致。需确保应用支持读写分离。
Rollback: 切回主库,关闭副本连接
Customer impact
黑五期间,用户访问商品详情页时遇到高延迟(15 秒)或间歇性 503 错误,影响浏览和下单体验。预计影响所有通过首页和营销邮件进入的用户,约占当前流量的 80%。
Postmortem draft
Summary
09:00 UTC 黑五流量高峰期间,catalog-svc 因缓存雪崩导致数据库 CPU 100%,p99 延迟飙升至 15 秒,间歇性 503 错误。所有商品详情页请求绕过缓存直接查询数据库,影响用户浏览和下单。
Timeline (UTC)
[FILL IN]
Impact
- 用户可见的 503 错误率 8%
- p99 延迟 15 秒(基线 80ms)
- 数据库 CPU 100% 持续 30 分钟
- 影响所有商品详情页请求
Root Cause
缓存 TTL 统一设置为 7 小时,导致所有 catalog:item:* 键在 09:00 UTC 同时过期,黑五流量 12 倍于正常,引发缓存雪崩。
Detection
09:02 UTC 收到 DBHighCPU、CatalogSvcLatencyHigh、CheckoutErrorRate 告警。
Response
[FILL IN]
What Went Well
- 告警及时,监控覆盖关键指标
- Redis 缓存 miss 率指标帮助快速定位
What Went Poorly
- 缓存 TTL 未设置抖动,导致同时过期
- 未对黑五流量进行压测和容量规划
- 缺乏缓存预热机制
Action Items
- [ ] 为缓存 TTL 添加随机抖动,避免同时过期
- [ ] 实现缓存预热脚本,在流量高峰前主动填充缓存
- [ ] 对 catalog-svc 进行黑五流量压测
- [ ] 增加数据库连接池监控和自动扩容
Follow-ups
- P0为 catalog:item:* 缓存 TTL 添加随机抖动(如 7h ± 30min)— 服务所有者
- P0实现缓存预热脚本,在流量高峰前主动填充热门商品缓存— 平台团队
- P1对 catalog-svc 进行黑五流量压测,验证缓存雪崩场景— QA 团队
- P1增加数据库连接池使用率和查询队列长度的告警— 可观测性团队
- P2评估引入分布式缓存或本地缓存层,减少对 Redis 的依赖— 架构团队
- P2审查 Redis 驱逐策略和内存配置,确保缓存容量充足— SRE 团队
Similar past incidents
lexical match (pg_trgm)
- 82%
[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%
- 66%
[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%
- 47%
[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%
- 42%
[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] Regional 5xx spike after DNS TTL change
us-west-2 region: 35% 502 errors, p99 4s. us-east-1: normal. New DNS record deployed 30min before incident.