1. 缓存穿透概述
1.1 什么是缓存穿透
缓存穿透(Cache Penetration)是指客户端请求的数据在缓存层和数据库层中均不存在,导致每次请求都直接穿透缓存层,直达后端数据库。由于缓存层无法命中,所有请求压力全部落在数据库上,形成“缓存失效 → 数据库直击”的恶性循环。
核心定义:缓存穿透 = 缓存未命中 + 数据库无记录 → 请求绕过缓存直接攻击数据库。
与缓存击穿(热点 key 过期)和缓存雪崩(大量 key 同时过期)不同,穿透问题的本质是数据本身不存在,而非缓存数据失效。因此,即使缓存服务完全正常,穿透依然会发生。
1.2 穿透对系统的危害
缓存穿透并非“小概率事件”,一旦被恶意利用或触发高频空查询,会对系统造成连锁破坏。下表总结了穿透在不同层面的危害表现:
| 危害维度 | 具体表现 | 严重程度 |
|---|---|---|
| 数据库连接耗尽 | 每次穿透都占用一个数据库连接,连接池迅速枯竭,正常请求也被阻塞 | ★★★★★ |
| 数据库 CPU/IO 飙升 | 大量空查询导致数据库执行全表扫描或索引无效扫描,CPU 和磁盘 IO 瞬间打满 | ★★★★★ |
| 响应延迟雪崩 | 数据库变慢后,所有依赖该数据库的接口响应时间从毫秒级退化到秒级甚至超时 | ★★★★☆ |
| 缓存层资源浪费 | 缓存服务器虽然未命中,但仍消耗网络带宽和连接资源,影响正常缓存查询 | ★★★☆☆ |
| 业务数据污染 | 穿透导致大量空结果被误写入缓存(若代码逻辑不当),挤占正常缓存空间 | ★★★☆☆ |
| 系统级连锁故障 | 数据库宕机 → 应用层重试风暴 → 负载均衡过载 → 整个服务集群不可用 | ★★★★★ |
⚠️ 真实案例警示:某电商平台在促销期间,爬虫批量请求不存在的商品 ID(如负数 ID、超长 ID),导致数据库每秒承受超过 20 万次空查询,连接池 3 秒内耗尽,核心商品查询接口完全瘫痪 15 分钟,直接损失超百万。
1.3 穿透发生的典型场景
缓存穿透并非只出现在恶意攻击中,正常业务逻辑同样可能触发。以下是生产环境中最常见的六类穿透场景:
- 恶意攻击 / 爬虫扫描
攻击者构造大量不存在的 key(如负数 ID、随机字符串、超长参数)发起请求,利用缓存空挡耗尽数据库资源。 - 业务查询不存在的数据
用户查询已删除的商品、已注销的账号、过期的订单等,缓存和数据库均无记录。 - 批量导入 / 数据同步间隙
数据尚未同步到缓存或数据库时,前端已经发起查询请求,导致穿透。 - 缓存预热不完整
新上线服务或重启后,缓存中只有部分热点数据,大量非热点 key 直接穿透。 - 分页 / 列表查询空结果
查询条件过于严格导致数据库返回空列表,且该空结果未被缓存。 - 参数校验缺失
前端或网关未对参数做合法性校验,非法参数(如空值、越界值)直接穿透到后端。
1.4 穿透与击穿、雪崩的区别
很多开发者容易混淆缓存穿透、缓存击穿和缓存雪崩。下表从触发原因、影响范围和典型特征三个维度进行对比:
| 概念 | 触发原因 | 影响范围 | 典型特征 |
|---|---|---|---|
| 缓存穿透 | 请求的数据在缓存和数据库中都不存在 | 单个 key 或批量不存在的 key | 缓存未命中 + 数据库空结果 |
| 缓存击穿 | 热点 key 在缓存中过期失效 | 单个热点 key | 高并发瞬间涌入数据库 |
| 缓存雪崩 | 大量 key 同时过期或缓存节点宕机 | 大面积 key 或整个缓存集群 | 数据库瞬间被海量请求淹没 |