api-home-x 的异常第一眼很像数据库扛不住接口 P99 上升数据库 CPU 冲高active connections 从 120 涨到 780。但这类问题最容易误判。数据库被打满只是结果真正要确认的是它是 SQL 变慢导致连接堆积还是缓存失效后回源请求突然放大把原本正常的 SQL 执行量打爆。这次的关键判断点不在某一条慢 SQL而在三条曲线是否同一时间拐头缓存命中率、回源 QPS、数据库连接数。现场最有价值的不是 CPU而是命中率故障窗口里入口流量有活动带来的上升但没有到完全解释数据库压力的程度。先看缓存侧指标redis get QPS: 90k - 42k cache.hit.ratio: 96% - 61% cache.miss.count: 与 db.query.count 同步上升 TTL 分布: 大量 key 集中在 10:00 前后过期这组数据基本把方向从“Redis 变慢”推到了“Redis 没命中”。redis get QPS下降不是因为请求少了而是大量请求在 miss 后直接进入回源路径。命中率从 96% 掉到 61%对首页这种高频接口来说意味着原本被缓存挡住的请求被成批放到了数据库上。更危险的是 TTL 分布。大量 key 在 10:00 前后集中失效这不是单个热点 key 的击穿而更接近批量过期造成的雪崩同时活动页配置 keyredis:key:home:activity:x又存在单 key miss 后并发重建的问题所以现场是“雪崩里夹着击穿”。为什么不是数据库自己变慢数据库指标看起来很吓人db active connections: 120 - 780 db CPU: 35% - 92% api-home-x 相关 SQL: 单次耗时未明显变慢 Rows_examined: 稳定 执行计划: 稳定如果是 SQL 计划退化通常会看到单次 SQL 耗时、扫描行数、临时表、排序或锁等待出现明显变化。但这里Rows_examined和执行计划稳定说明 SQL 本身没有突然变成另一个执行路径。真正变化的是请求量。缓存 miss 和数据库 query count 同步上升active connections 随之被推高。数据库 CPU 到 92%不是因为每条 SQL 更重而是大量原本应该命中缓存的请求同时回源。这个结论很关键。处理 SQL 慢和处理缓存雪崩是两套动作前者看索引、执行计划和锁后者要先挡住回源放大否则即使临时扩数据库也可能只是把故障窗口延后几分钟。放大链路TTL 集中过期 无互斥重建这次链路可以简化成四步活动开始前后大量首页相关缓存 key 的 TTL 集中到期。api-home-x读缓存时命中率快速下降。缓存重建没有互斥保护同一个 key miss 后并发请求同时查询数据库。数据库连接数和 CPU 被回源请求推满接口延迟继续升高进一步放大排队。这里有两个边界需要区分。第一它不是典型 Redis hot key 主导。hot key 常见表现是某个分片、某个 key 或某类命令访问极端倾斜Redis 节点 CPU、网络或代理层 key 分布会先异常。本案里 Redis 单分片没有明显倾斜问题核心是 miss 后的回源。第二它也不是单纯缓存穿透。穿透通常是大量不存在的数据持续打到后端需要看空值缓存、参数校验或布隆过滤器。本案有明确 TTL 集中过期和活动页 key 重建并发主线仍是击穿与雪崩。止血要先控制回源而不是只扩数据库应急阶段的优先级是把数据库从并发回源里解出来动作目的验证指标对 api-home-x 做临时限流或降级兜底降低回源并发峰值DB active connections 回落对活动页核心 key 做临时预热和续期恢复高频 key 命中cache.hit.ratio 回升给缓存重建加互斥保护避免同一 key 并发回源单 key miss 后 DB query 不再成倍放大对非核心模块使用短期兜底数据保住首页主链路接口 P99 和超时率下降根治阶段不能只写“缓存加随机 TTL”这么一句。至少要补齐三类机制TTL 随机化同一批缓存不要在同一时间点过期尤其是活动页、首页、配置类 key。重建保护热点 key miss 后只允许一个线程或一个实例回源重建其余请求等待、复用旧值或走降级。热点预热与续期活动开始前预热核心 key活动中对高频 key 做续期或异步刷新避免自然过期撞上流量峰值。修复后的验证口径也要闭环命中率恢复到稳定水位miss count 与 DB query count 不再同向暴涨DB active connections 回到基线附近api-home-xP99 和超时率同步下降。常用排查命令下面这组命令适合排查缓存击穿、雪崩和数据库被回源打满的问题。不要只看单点输出要把时间线对齐。redis-cli -h host -p port info stats看keyspace_hits、keyspace_misses、instantaneous_ops_per_sec确认命中率和 miss 是否在故障窗口突变。redis-cli -h host -p port info commandstats看get、mget、set等命令调用量和耗时判断是读缓存变慢还是 miss 后回源变多。redis-cli -h host -p port --hotkeys redis-cli -h host -p port --bigkeys谨慎在线执行主要用于排除 hot key、big key 或异常数据结构导致的 Redis 服务端瓶颈。redis-cli -h host -p port slowlog get 20看是否存在慢命令。如果 Redis 慢日志干净而 DB 压力同步上升更应该怀疑回源放大。SHOW FULL PROCESSLIST; EXPLAIN ANALYZE sql; SHOW ENGINE INNODB STATUS\G看数据库端连接是否大量卡在同类查询上并确认 SQL 执行计划、扫描行数、锁等待是否真的变化。grep api-home-x access.log | awk {print $NF} | sort -n | tail抽样看接口耗时分布。入口 P99、缓存 miss、DB 连接数三者同向变化时排查方向会比单看 CPU 更稳。复盘时要追问的 4 个问题这类故障的直接原因是缓存批量失效后并发回源数据库被请求量放大打满。根因不只是 TTL 集中而是缺少缓存重建互斥、热点 key 预热续期和回源预算。TTL 是触发器防护缺口才是故障能扩大的原因。后续复盘可以重点追问四件事核心缓存 key 的 TTL 是否集中是否按业务批次一起写入。miss 后是否允许并发回源是否有互斥、请求合并或旧值兜底。活动、发布、任务开始前是否有缓存预热和命中率看板。缓存层是否配置了回源限流数据库是否有连接池等待、active connections、query count 的联动告警。缓存不是数据库的加速插件而是容量模型的一部分。只要缓存失效能把请求原样放回数据库就必须按“后端能承受多少回源”来设计而不是按“平时命中率很高”来安慰自己。