2. 缓存击穿与雪崩:区别、成因、典型场景及连锁反应
在高并发系统中,缓存层是抵御数据库压力的第一道防线。然而,当这道防线出现局部或大面积失效时,系统将面临两种截然不同但同样危险的故障模式:缓存击穿与缓存雪崩。理解二者的本质区别、触发条件及连锁反应,是设计穿透保护方案的前提。
2.1 核心概念对比
| 对比维度 | 缓存击穿 | 缓存雪崩 |
|---|---|---|
| 失效范围 | 单个热点 key | 大量 key 同时失效 |
| 失效时机 | 缓存过期瞬间 | 同一时间窗口内批量过期 |
| 并发特征 | 高并发请求集中攻击同一个 key | 高并发请求分散攻击多个失效 key |
| 数据库压力 | 单点压力极高,可能击穿单库 | 整体压力飙升,拖垮整个集群 |
| 恢复难度 | 相对可控,恢复较快 | 极易引发级联故障,恢复困难 |
一句话区分:击穿是“一把枪打一个点”,雪崩是“万箭齐发覆盖整个战场”。
2.2 缓存击穿:成因与典型场景
2.2.1 成因分析
缓存击穿的核心成因是热点 key 在过期瞬间遭遇超高并发请求。当某个 key 的访问量占整体流量的 30% 以上时,一旦该 key 在缓存中消失,所有请求同时穿透到数据库,数据库连接池瞬间被占满,查询响应时间急剧上升。
- 过期时间设置不当:所有请求都依赖同一个过期时间点。
- 热点数据未做特殊保护:普通 key 与热点 key 使用相同的过期策略。
- 缓存重建成本高:数据库查询 + 业务计算耗时超过 200ms,导致请求堆积。
2.2.2 典型场景
- 电商秒杀商品详情:一个爆款商品的缓存过期,数万用户同时刷新页面。
- 社交平台热搜榜单:某条新闻在整点过期,大量用户同时访问该话题。
- 金融行情快照:某只股票的分时数据缓存过期,所有行情客户端同时拉取。
实战案例:某电商平台大促期间,一个爆款商品的缓存 TTL 设置为 60 分钟,整点过期后 10 秒内数据库连接数从 50 飙升至 2000,导致该商品所在分库的 CPU 使用率瞬间达到 100%,影响同库其他商品的正常查询。
2.3 缓存雪崩:成因与典型场景
2.3.1 成因分析
缓存雪崩的成因更为复杂,通常由批量失效或缓存节点宕机引发。当大量 key 在同一时间窗口内过期,或者缓存集群中的多个节点同时不可用时,所有请求直接穿透到数据库层,数据库负载呈指数级增长,最终导致数据库连接池耗尽、查询超时、服务不可用。
- 批量过期:所有 key 使用相同的 TTL(如 3600 秒),导致整点集体失效。
- 缓存节点宕机:Redis 主从切换、集群扩容或网络分区导致大量 key 不可访问。
- 缓存服务重启:缓存服务重启后,所有 key 丢失,冷启动期间数据库承受全部流量。
2.3.2 典型场景
- 每日零点数据刷新:所有报表、排行榜、推荐数据的缓存同时过期。
- 缓存集群故障:Redis Cluster 中多个主节点同时宕机,大量 key 无法命中。
- 缓存服务升级重启:灰度发布或故障恢复后,缓存中无数据,数据库瞬间被打满。
2.4 连锁反应与故障传导路径
无论是击穿还是雪崩,一旦数据库层被穿透,故障会沿着调用链逐级传导,形成典型的级联故障模式。下图展示了从缓存失效到系统雪崩的完整传导路径。
2.5 连锁反应的关键指标
当缓存失效引发穿透时,以下指标会依次出现异常,可作为故障预警的参考依据:
| 阶段 | 监控指标 | 异常阈值 | 典型表现 |
|---|---|---|---|
| 缓存层 | 缓存命中率 | 低于 80% | 命中率从 95% 骤降至 30% |
| 数据库层 | 活跃连接数 | 超过连接池上限的 80% | 连接数从 50 飙升至 500 |
| 数据库层 | 慢查询数量 | 每秒超过 10 个 | 大量简单查询变为慢查询 |
| 应用层 | 接口 P99 延迟 | 超过 1000ms | 从 50ms 飙升至 3000ms |
| 应用层 | 错误率 | 超过 5% | 超时错误和连接拒绝错误激增 |
2.6 击穿与雪崩的连锁反应差异
虽然二者最终都可能导致系统雪崩,但连锁反应的路径和速度存在明显差异:
- 击穿的连锁反应:单 key 失效 → 数据库单点压力激增 → 该库连接池耗尽 → 同库其他查询排队超时 → 影响范围逐步扩大。整个过程通常持续 5-30 秒,如果热点 key 重建速度快,系统可自行恢复。
- 雪崩的连锁反应:大量 key 失效 → 数据库整体压力飙升 → 所有连接池同时耗尽 → 应用线程阻塞 → 上游服务超时重试 → 流量放大 → 系统全面崩溃。整个过程通常在 10 秒内完成,恢复需要人工介入。
经验法则:缓存击穿是“局部战争”,缓存雪崩是“全面战争”。击穿可以通过热点 key 隔离和互斥锁解决;雪崩则需要从 TTL 分布、缓存高可用、限流降级三个维度综合治理。
2.7 故障模拟与验证方法
在生产环境或压测环境中,可以通过以下方式验证系统对击穿和雪崩的防护能力:
- 热点 key 过期测试:手动设置一个高访问频率 key 的 TTL 为 5 秒,观察过期瞬间数据库连接数和接口延迟的变化。
- 批量过期测试:将一批 key 的 TTL 设置为相同的较短时间(如 10 秒),观察数据库压力曲线是否出现尖峰。
- 缓存节点故障测试:通过混沌工程工具随机杀死一个 Redis 节点,观察系统是否触发降级和限流。
- 冷启动测试:重启缓存服务后,观察数据库负载是否在可接受范围内,以及缓存预热机制是否生效。
# 压测脚本示例:模拟热点 key 过期
# 使用 wrk 对单个热点 key 进行高并发请求
wrk -t 10 -c 200 -d 30s \
--latency \
http://api.example.com/hot-item/10001
# 观察指标:
# 1. 缓存命中率是否骤降
# 2. 数据库活跃连接数是否飙升
# 3. 接口 P99 延迟是否超过 500ms