缓存穿透:定义、场景与危害

大家好,我是你们的老朋友。今天咱们来聊聊缓存穿透——这个听起来有点抽象,但实际杀伤力极强的“隐形杀手”。

先问大家一个问题:你的缓存系统,真的能挡住所有无效请求吗?

很多同学觉得,只要用了缓存,数据库就安全了。但现实往往很打脸。我在项目中就遇到过这么一次:某个查询接口突然被打满,数据库 CPU 直接飙到 100%,整个服务差点挂掉。排查下来,罪魁祸首就是缓存穿透。

什么是缓存穿透?

说白了,缓存穿透就是请求绕过了缓存,直接打到了数据库上。

正常的流程是这样的:

  1. 用户请求数据
  2. 先去缓存里查
  3. 缓存有,直接返回(缓存命中)
  4. 缓存没有,去数据库查
  5. 数据库有,回写缓存,返回结果

但缓存穿透不一样。它发生在缓存和数据库里都没有这条数据的时候。

你想想看:缓存里没有,去数据库查,数据库也没有。那这次查询就白费了。更可怕的是,如果这种请求量很大,数据库就会被反复“穿透”,直到扛不住。

核心定义:缓存穿透是指查询一个根本不存在的数据,由于缓存和数据库中都没有该数据,导致每次请求都直接落到数据库上,缓存形同虚设。

穿透发生的典型场景

我总结了几种最常见的穿透场景,大家可以对照一下自己的项目:

场景 描述 真实案例
恶意攻击 攻击者故意构造大量不存在的 key 进行请求 遍历用户 ID,请求不存在的用户信息
业务漏洞 前端未做参数校验,传入非法参数 商品详情页传入负数 ID
数据删除 缓存和数据库中的数据被正常删除后,仍有大量请求 热门活动结束后,用户还在访问活动页
缓存过期 热点数据刚好过期,大量请求同时穿透 秒杀商品缓存失效瞬间

嗯,这里要注意:恶意攻击是最危险的。我记得有一次做安全审计,发现某个接口的 QPS 异常高,全是请求不存在的用户 ID。攻击者用脚本跑了一个循环,从 1 到 1000000 挨个试。如果没有防护,数据库早就挂了。

穿透对系统的危害

缓存穿透的危害,不是“慢一点”那么简单。它可能引发连锁反应,最终导致整个系统崩溃。

1. 数据库压力暴增

这是最直接的危害。正常情况下,缓存能挡住 90% 以上的请求。一旦发生穿透,所有请求都落到数据库上。数据库的连接池是有限的,撑不住就会拒绝连接。

我曾经见过一个案例:某个查询接口平时 QPS 是 5000,缓存命中率 95%。穿透发生后,数据库要扛 5000 QPS,直接打满。数据库 CPU 从 20% 飙到 100%,响应时间从 5ms 变成 5s。

2. 服务雪崩

数据库扛不住,就会拖慢所有依赖它的服务。你想想看:

  • 数据库连接池满了
  • 新的请求排队等待
  • 等待超时,前端重试
  • 重试带来更多请求
  • 恶性循环,系统崩溃

这就是典型的雪崩效应。一个点的故障,扩散到整个系统。

3. 资源浪费

每次穿透查询,都要走一遍完整的链路:

  • 网络传输
  • 序列化/反序列化
  • 数据库查询
  • 结果返回

这些操作消耗 CPU、内存、网络带宽。对于不存在的 key,这些消耗完全是浪费的。如果穿透量很大,服务器资源就会被无效请求占满,正常用户反而得不到服务。

4. 缓存失效

这一点容易被忽略。穿透请求虽然查不到数据,但会挤占缓存的有效空间。

举个例子:你的缓存容量是 1GB,正常能存 100 万条热点数据。如果穿透请求把大量不存在的 key 也写进缓存(比如存空值),就会挤掉真正的热点数据。缓存命中率下降,又导致更多请求穿透到数据库。

避坑指南:我曾经接手过一个项目,缓存命中率只有 30%。排查后发现,代码里把所有查询结果都缓存了,包括空结果。结果缓存里全是“不存在”的数据,真正的热点数据反而被淘汰了。这就是穿透带来的二次伤害。

穿透的底层原理

为了让大家理解得更透彻,我画了一张流程图,展示穿透发生的完整链路:

缓存穿透请求链路 用户请求 查询缓存 缓存未命中 查询数据库 数据不存在 返回空结果 ⚠ 关键问题: 每次请求都走完整链路(缓存→数据库),且数据库查询结果为空,无法回写缓存。

从这张图可以看得很清楚:穿透的核心问题在于“查不到”。缓存查不到,数据库也查不到,结果就是每次请求都白跑一趟数据库。

穿透的量化影响

咱们用数据说话。假设一个系统:

  • 正常 QPS:5000
  • 缓存命中率:95%
  • 数据库能承受的最大 QPS:1000

正常情况下,打到数据库的 QPS 是 5000 × 5% = 250,数据库很轻松。

但如果发生穿透:

  • 假设 20% 的请求是穿透请求(1000 QPS)
  • 这些请求全部打到数据库
  • 加上正常的 250 QPS,数据库总 QPS 达到 1250
  • 超过数据库承载上限,开始出现超时

你看,只需要 20% 的穿透请求,就能把数据库打垮。

我的经验:在实际项目中,穿透请求的比例往往比想象的高。尤其是做活动的时候,用户会疯狂刷新页面,或者爬虫在扫描接口。我建议大家在设计系统时,默认就要假设穿透会发生,而不是等出问题了再补救。

小结

缓存穿透的本质,就是无效请求绕过了缓存保护。它的危害是连锁性的:从数据库压力暴增,到服务雪崩,再到资源浪费和缓存失效,一环扣一环。