2. 缓存穿透原理

2.1 缓存穿透的定义

缓存穿透(Cache Penetration)是指查询一个根本不存在的数据时,缓存层和数据库层都无法命中该数据。由于缓存层没有存储该数据的副本,每次请求都会绕过缓存,直接穿透到数据库层执行查询。当大量并发请求查询同一个不存在的 key 或一组不存在的 key 时,数据库会承受巨大的查询压力,甚至可能导致数据库服务崩溃。

核心特征:缓存层与数据库层均无数据 → 请求绕过缓存 → 直接压向数据库。

2.2 发生场景分析

缓存穿透并非偶发故障,而是由业务逻辑或攻击行为引发的系统性风险。以下为最常见的三类发生场景:

场景类别 典型示例 请求特征 危害等级
业务正常查询 用户查询已下架商品、已注销账号、过期订单 少量、偶发、符合业务预期 低
恶意攻击 遍历不存在的 ID(如 -1、0、9999999) 大量、高频、参数异常 高
缓存与数据库数据不一致 缓存淘汰后数据库记录被物理删除 突发、集中、难以预测 中
注意:恶意攻击场景下,攻击者往往利用业务 ID 生成规律(如自增主键)构造大量无效请求,使缓存层完全失效,数据库成为唯一瓶颈。

2.3 对数据库的压力影响

缓存穿透对数据库的压力影响可以通过以下量化指标来理解。假设系统正常状态下缓存命中率为 95%,数据库每秒处理能力为 1000 QPS:

  • 正常状态:1000 次请求 → 缓存命中 950 次 → 数据库仅处理 50 次查询 → 数据库负载 5%
  • 穿透攻击状态:1000 次请求 → 缓存命中 0 次 → 数据库处理 1000 次查询 → 数据库负载 100%
  • 压力放大效应:数据库 QPS 瞬间增长 20 倍,连接池耗尽,响应超时,引发级联故障
经验数据:实际生产环境中,一次针对不存在的商品 ID 的穿透攻击,可在 30 秒内将数据库 QPS 从 200 推高至 8000+,导致数据库连接池满、慢查询堆积、主从延迟飙升。

2.4 缓存穿透流程示意图

下图展示了正常查询与缓存穿透查询的路径差异,清晰呈现穿透发生时请求如何绕过缓存直接冲击数据库:

缓存穿透流程对比图 缓存穿透流程对比:正常查询 vs 穿透查询 正常查询(缓存命中) 客户端请求 缓存层(命中) 返回数据 数据库(未访问) 穿透查询(缓存未命中) 客户端请求 缓存层(未命中) 数据库(承受压力) 返回空结果 ⚠ 数据库 QPS 飙升,连接池耗尽

2.5 穿透压力传导链

缓存穿透的压力并非孤立事件,而是沿着系统调用链逐级传导,形成典型的压力放大效应:

  1. 入口层:大量无效请求涌入 API 网关或负载均衡器
  2. 应用层:业务逻辑层反复查询缓存,每次均返回 null
  3. 缓存层:缓存未命中,请求穿透至数据库访问层
  4. 数据库层:数据库执行全表扫描或索引查找,返回空结果集
  5. 级联效应:数据库连接池耗尽 → 正常查询超时 → 应用线程阻塞 → 服务雪崩
关键结论:缓存穿透的本质是缓存层保护失效。当缓存无法拦截无效查询时,数据库成为唯一的兜底层,而数据库的设计目标并非应对高频空查询,因此极易成为系统瓶颈。

2.6 穿透与击穿、雪崩的对比

为帮助学员建立清晰的概念边界,下表对比了缓存穿透与另外两种常见缓存故障:

故障类型 触发条件 缓存状态 数据库影响 典型修复手段
缓存穿透 查询不存在的数据 始终未命中 大量空查询压力 布隆过滤器、空值缓存
缓存击穿 热点 key 过期 瞬间未命中 单 key 高并发回源 互斥锁、逻辑过期
缓存雪崩 大量 key 同时过期 / 缓存宕机 大面积未命中 海量回源压力 过期时间随机化、缓存高可用
学习提示:穿透、击穿、雪崩是缓存保护的三类核心问题。穿透关注的是“数据不存在”,击穿关注的是“热点过期”,雪崩关注的是“大规模失效”。理解三者的区别是设计保护算法的前提。