1. 缓存穿透问题定义
1.1 什么是缓存穿透
缓存穿透是指客户端请求的数据在缓存层和数据库层中均不存在,导致每次请求都直接穿透缓存层,直达数据库层。由于缓存层无法命中,所有请求压力全部落在数据库上,造成数据库负载急剧上升,甚至引发数据库宕机。
核心特征:缓存未命中 + 数据库无记录 = 每次请求都穿透到数据库。
典型的穿透场景包括:
- 恶意攻击:攻击者构造大量不存在的 Key(如负 ID、超长字符串)发起请求。
- 业务漏洞:查询条件错误导致 Key 不存在,例如查询已删除的商品详情。
- 数据同步延迟:上游数据未及时写入数据库,缓存和数据库均无对应记录。
1.2 穿透对数据库的压力模型
缓存穿透对数据库的压力可以用以下数学模型描述:
| 参数 | 符号 | 说明 |
|---|---|---|
| 请求总数 | Q | 单位时间内到达的请求量 |
| 缓存命中率 | H | 正常业务下缓存命中比例(通常 90%+) |
| 穿透请求比例 | P | 请求中 Key 不存在的比例 |
| 数据库承受请求量 | D | 实际到达数据库的请求数 |
在无穿透保护时,数据库承受的请求量为:
D = Q × (1 - H) + Q × P
当 P 接近 1(恶意攻击)且 H 接近 0(缓存完全失效)时,D ≈ Q,即数据库承受全部请求压力。相比正常场景(D ≈ Q × 0.1),压力放大 10 倍以上。
压力放大效应:穿透请求的响应时间通常比正常请求更长(数据库查询空结果仍需消耗 IO),导致数据库连接池快速耗尽,引发级联故障。
1.3 穿透与击穿/雪崩的区别
缓存穿透、缓存击穿、缓存雪崩是三种不同的缓存故障模式,常被混淆。下表从故障原因、影响范围、发生时机三个维度进行对比:
| 故障类型 | 故障原因 | 影响范围 | 发生时机 | 典型场景 |
|---|---|---|---|---|
| 缓存穿透 | 请求的 Key 在缓存和数据库中均不存在 | 单个 Key 或少量 Key | 持续发生,与缓存过期无关 | 恶意攻击、查询无效 ID |
| 缓存击穿 | 热点 Key 过期瞬间,大量并发请求直达数据库 | 单个热点 Key | 热点 Key 过期瞬间 | 秒杀商品、爆款文章 |
| 缓存雪崩 | 大量 Key 同时过期或缓存节点宕机 | 大量 Key 或全量 Key | 缓存集中过期或节点故障时 | 缓存服务重启、统一过期时间 |
记忆口诀:穿透查不到,击穿热key倒,雪崩一大片。三种故障的治理策略完全不同,穿透依赖空值缓存/布隆过滤器,击穿依赖互斥锁/永不过期,雪崩依赖过期时间随机化/高可用集群。
1.4 穿透问题的危害评估
缓存穿透对生产环境的危害主要体现在以下四个方面:
- 数据库连接耗尽:穿透请求占用数据库连接,正常请求无连接可用,引发服务不可用。
- 响应时间飙升:数据库查询空结果仍需消耗磁盘 IO 和 CPU,RT 从毫秒级升至秒级。
- 资源浪费:缓存层和数据库层均做无效计算,系统吞吐量大幅下降。
- 安全风险:恶意穿透攻击可导致系统拒绝服务(DoS),影响业务连续性。
生产案例:某电商平台在促销期间遭遇恶意穿透攻击,攻击者构造大量不存在的商品 ID 发起查询,导致数据库 QPS 从 2000 飙升至 25000,数据库连接池耗尽,核心交易链路中断 12 分钟。事后分析发现,未对不存在的 Key 做空值缓存,也未使用布隆过滤器进行前置过滤。