4. 缓存一致性基础:缓存穿透、缓存击穿、缓存雪崩的定义与典型场景
在分布式限流熔断治理中,缓存层是抵御突发流量、保护后端数据库的第一道防线。然而,缓存层自身的故障模式——缓存穿透、缓存击穿、缓存雪崩——会直接导致请求绕过缓存直击数据库,引发级联故障。理解这三种故障的定义、成因与典型场景,是定位缓存一致性故障的前提。
4.1 三种故障的核心定义与对比
| 故障类型 | 定义 | 核心成因 | 影响范围 |
|---|---|---|---|
| 缓存穿透 | 请求查询一个一定不存在的数据,缓存和数据库都查不到,每次请求都穿透到数据库。 | 恶意攻击或业务漏洞(如查询不存在的用户ID) | 单点持续攻击,数据库压力线性增长 |
| 缓存击穿 | 一个热点 key 在缓存失效的瞬间,大量并发请求同时穿透到数据库。 | 热点 key 过期 + 高并发 | 单 key 瞬时击穿,数据库单点压力暴增 |
| 缓存雪崩 | 大量缓存 key 在同一时间失效,或缓存节点宕机,导致所有请求涌向数据库。 | 批量 key 同时过期 / 缓存集群故障 | 全局性故障,数据库可能直接被压垮 |
治理视角提示:在 OpenAPI 限流熔断治理中,缓存穿透通常由参数校验层拦截;缓存击穿需要热点 key 自动续期或互斥锁;缓存雪崩则依赖缓存高可用架构与过期时间随机化。三种故障的治理策略不同,但都会引发缓存一致性告警。
4.2 缓存穿透:空查询的陷阱
典型场景:攻击者构造大量不存在的用户 ID(如负数、超长数字)请求用户信息接口。缓存中无此 key,数据库中也无此记录,每次请求都直接查询数据库。
- 危害:数据库连接数被无效查询耗尽,正常请求被阻塞。
- 缓存一致性表现:缓存命中率骤降,数据库 QPS 飙升,限流器频繁触发。
- 常见治理手段:缓存空值(设置短 TTL)、布隆过滤器前置拦截。
4.3 缓存击穿:热点 key 的瞬间崩塌
典型场景:某电商平台的爆款商品详情页,缓存 key 为 product:12345。该 key 在缓存中的 TTL 恰好到期,此时数千个并发请求同时读取该 key,全部未命中缓存,直接查询数据库。
- 危害:数据库单行记录被高频查询,行锁竞争激烈,响应时间飙升。
- 缓存一致性表现:缓存命中率在某一秒内断崖式下跌,数据库 QPS 出现尖峰。
- 常见治理手段:互斥锁(只允许一个线程重建缓存)、热点 key 永不过期 + 异步更新。
限流熔断关联:缓存击穿发生时,限流器会检测到数据库 QPS 突增,可能触发熔断。但熔断后所有请求被拒绝,反而加剧用户体验恶化。正确的做法是优先使用互斥锁保护热点 key,而非依赖限流器兜底。
4.4 缓存雪崩:全局性的灾难
典型场景:某系统所有缓存 key 的过期时间统一设置为 1 小时。在整点时刻,大量 key 同时过期,所有请求同时穿透到数据库。或者,缓存集群中某台机器宕机,该机器上的所有 key 全部失效。
- 危害:数据库瞬间承受数倍于平时的流量,极易触发连接池耗尽、CPU 满载,导致数据库宕机。
- 缓存一致性表现:缓存命中率全局归零,数据库 QPS 达到峰值,系统整体响应时间急剧恶化。
- 常见治理手段:过期时间随机化(基础 TTL + 随机偏移)、缓存集群高可用(主从 + 哨兵)、本地缓存二级降级。
4.5 三种故障在限流熔断治理中的表现差异
| 故障类型 | 限流器触发特征 | 熔断器触发特征 | 缓存一致性告警特征 |
|---|---|---|---|
| 缓存穿透 | 持续低水平限流(无效请求不断) | 不易触发熔断(QPS 未达阈值) | 缓存命中率持续低位,数据库 QPS 缓慢上升 |
| 缓存击穿 | 瞬时尖峰限流(1秒内 QPS 暴增) | 可能触发熔断(错误率飙升) | 缓存命中率断崖式下跌,数据库 QPS 尖峰 |
| 缓存雪崩 | 全局性限流(所有接口 QPS 暴涨) | 大概率触发熔断(全局超时) | 缓存命中率全局归零,数据库 QPS 达到峰值 |
故障定位陷阱:当限流器频繁触发时,不要只关注限流阈值配置。先检查缓存命中率指标——如果命中率正常,可能是流量突增;如果命中率异常,则优先排查缓存穿透/击穿/雪崩。这是区分“真实流量过载”与“缓存故障导致过载”的关键。
4.6 典型故障排查步骤
- 查看缓存命中率曲线:如果命中率从 95% 骤降至 10% 以下,优先怀疑缓存雪崩或击穿。
- 检查 key 过期分布:使用
redis-cli --bigkeys或类似工具,查看是否有大量 key 在同一时间过期。 - 分析请求日志:筛选出缓存未命中的请求,查看请求的 key 是否集中在一个热点 key(击穿)还是分散在大量不存在的 key(穿透)。
- 验证数据库 QPS 与缓存 QPS 的比例:正常情况下数据库 QPS 应远小于缓存 QPS;如果比例接近 1:1,说明缓存基本失效。
- 检查限流器日志:限流触发的时间点是否与缓存命中率下跌的时间点吻合。
# 示例:使用 Redis 命令检查 key 过期时间分布
redis-cli --scan --pattern "product:*" | head -100 | while read key; do
ttl=$(redis-cli ttl "$key")
echo "$key TTL: $ttl"
done
# 如果大量 key 的 TTL 集中在同一秒,说明存在雪崩风险
最佳实践:在 OpenAPI 网关层统一记录缓存命中/未命中日志,并关联限流事件 ID。这样在故障定位时,可以快速关联“限流触发 → 缓存未命中 → 数据库压力”的完整链路。