2. 缓存一致性基础:缓存穿透、缓存击穿、缓存雪崩的定义与区别
在分布式系统中,缓存层是抵御高并发、保护后端数据库的第一道防线。然而,当缓存策略设计不当或遭遇极端流量时,会出现三种典型的缓存故障模式:缓存穿透、缓存击穿和缓存雪崩。这三种故障虽然名称相似,但成因、影响范围和治理手段截然不同。理解它们的本质区别,是后续进行契约测试与版本管理故障排查的前提。
2.1 三种故障的定义与核心特征
| 故障模式 | 核心定义 | 攻击目标 | 数据特征 | 典型后果 |
|---|---|---|---|---|
| 缓存穿透 | 请求查询一个根本不存在的数据,缓存和数据库都查不到,导致每次请求都穿透到数据库。 | 数据库 | key 不存在 | 数据库压力激增,可能引发宕机 |
| 缓存击穿 | 一个热点 key 在缓存中过期失效,同时大量并发请求涌入,全部打到数据库重建缓存。 | 数据库 + 热点 key | key 存在但过期 | 数据库瞬时高负载,响应延迟飙升 |
| 缓存雪崩 | 大量缓存 key 在同一时间过期失效,或缓存节点宕机,导致海量请求直接压向数据库。 | 数据库 | 批量 key 同时失效 | 数据库被击穿,系统级联崩溃 |
关键区分点: 穿透是“查不到”,击穿是“单个热点过期”,雪崩是“批量同时过期或节点宕机”。在契约测试中,这三种场景对应不同的版本兼容性断言和故障注入策略。
2.2 缓存穿透:空值查询的灾难
缓存穿透是最容易被忽视的故障。攻击者或异常客户端频繁请求数据库中不存在的数据(如恶意构造的 ID),缓存层因未命中而回源查询数据库,数据库也返回空结果,导致每次请求都绕过缓存直接访问数据库。
治理要点: 布隆过滤器(Bloom Filter)预判 key 是否存在;缓存空值(null object)并设置较短 TTL;接口层参数校验拦截非法请求。
2.3 缓存击穿:热点 key 的瞬间崩塌
缓存击穿只针对单个热点 key。当该 key 在缓存中过期时,恰好有成千上万的并发请求同时访问它。由于缓存未命中,所有请求同时回源查询数据库,数据库瞬间承受巨大压力,可能导致连接池耗尽。
版本管理关联: 在微服务版本升级过程中,如果热点 key 的缓存重建逻辑(如序列化/反序列化契约)发生变更,旧版本服务可能无法正确重建缓存,从而加剧击穿风险。契约测试需要覆盖“缓存过期后重建”这一临界状态的版本兼容性。
2.4 缓存雪崩:批量失效的系统级灾难
缓存雪崩是三种故障中影响范围最广的。常见诱因包括:
- 批量 TTL 相同: 所有缓存 key 设置了相同的过期时间,导致在同一时刻集体失效。
- 缓存节点宕机: Redis 集群中某个分片不可用,导致该分片上的所有 key 瞬间失效。
- 版本发布导致缓存清空: 新版本部署时强制刷新缓存,若未做预热,大量请求同时涌入数据库。
2.5 三种故障的对比关系图
下图从“请求目标”和“失效范围”两个维度,直观展示三种故障的定位差异:
2.6 三种故障的治理策略对比
| 治理策略 | 缓存穿透 | 缓存击穿 | 缓存雪崩 |
|---|---|---|---|
| 布隆过滤器 | ✅ 核心方案 | ❌ 不适用 | ❌ 不适用 |
| 缓存空值 | ✅ 常用方案 | ❌ 不适用 | ❌ 不适用 |
| 互斥锁 / 分布式锁 | ❌ 不适用 | ✅ 核心方案 | ❌ 不适用 |
| 热点 key 永不过期 | ❌ 不适用 | ✅ 辅助方案 | ❌ 不适用 |
| 随机 TTL / 过期时间打散 | ❌ 不适用 | ❌ 不适用 | ✅ 核心方案 |
| 缓存集群高可用 / 多级缓存 | ❌ 不适用 | ❌ 不适用 | ✅ 核心方案 |
| 版本发布缓存预热 | ❌ 不适用 | ✅ 辅助方案 | ✅ 辅助方案 |
契约测试视角: 在微服务版本迭代中,缓存穿透和击穿往往与数据序列化契约的版本兼容性密切相关。例如,当缓存中存储的是旧版本序列化的对象,而新版本服务尝试用新契约反序列化时,可能抛出异常导致缓存重建失败,进而诱发击穿。雪崩则更多与缓存配置契约(如 TTL 策略、集群拓扑)的版本管理相关。
2.7 三种故障的排查流程对比
当系统出现缓存相关故障时,可按照以下流程快速定位问题类型:
- 检查数据库 QPS 曲线: 如果数据库 QPS 出现瞬时尖峰,且尖峰宽度较窄(秒级),优先怀疑缓存击穿;如果尖峰持续较长时间(分钟级),优先怀疑缓存雪崩;如果数据库 QPS 持续异常但无明显尖峰,优先怀疑缓存穿透。
- 检查缓存命中率: 命中率骤降且持续低位,大概率是缓存穿透;命中率短暂下降后快速恢复,可能是缓存击穿;命中率断崖式下跌且涉及多个 key,是缓存雪崩的典型特征。
- 检查 key 的过期时间分布: 如果大量 key 的 TTL 集中在同一时间点,确认缓存雪崩;如果仅单个热点 key 过期,确认缓存击穿。
- 检查请求的 key 是否存在: 如果请求的 key 在数据库中也不存在,确认缓存穿透。
版本管理故障排查提示: 在微服务版本升级过程中,如果缓存故障发生在版本切换窗口,应重点检查新旧版本对缓存数据结构的契约是否一致。例如,旧版本缓存了字段 A+B,新版本期望读取字段 A+B+C,反序列化失败会导致缓存重建,进而触发击穿或雪崩。契约测试中的消费者驱动契约(CDC)可以有效捕获这类版本不兼容问题。