想靠背定义蒙混过关的,一到“那你会怎么解决”基本就卡壳了。我这些年做过不少缓存治理的复盘,也以面试官身份问过这个问题,发现“缓存穿透、击穿、雪崩”能被多少人答得漂亮,不完全取决于背得多熟,而是取决于你有没有真正理解缓存链路里每层方案的价值边界。这篇文章会把三兄弟的成因、差别、完整技术对策和面试表达技巧串一遍,目标是让你既能听明白,也能在真正的业务故障里用上。
1. 先看懂这道题的原始场景:缓存失效与数据库兜底之间的博弈
在讲任何名词之前,把底层场景拉出来看,后面一切都会顺很多。常规读请求的路径通常是:客户端请求先打到应用层,应用层先查 Redis,命中就直接返回;不命中则回源数据库,拿到数据后再把结果写回 Redis,顺便设置一个过期时间。
这套链路本身没有错,但一旦出现“缓存没挡住”的情况,流量就会砸到数据库头上。缓存穿透、缓存击穿、缓存雪崩,本质上都是同一个信号:有大量的请求因为某种原因没有从缓存里拿到想要的“现成结果”,于是被迫走了回源数据库这条路。它们的表象非常相似——数据库压力飙升、连接池被打满、慢查询增多、接口超时;但根因却完全不同,对应的解法也完全不同。
为什么我会强调“先理解场景”而不是“先背方案”?因为面试官考察的是你能否通过现象判断故障类型。同样是数据库被打挂,可能是有人拿着不存在的 ID 不停刷接口,也可能是某个热点 key 恰好到了过期时间,还可能是凌晨批量任务把大量 key 同时设置成了同一个过期时刻。如果你只知道“穿透用布隆过滤器,击穿用互斥锁,雪崩用随机过期”,一旦面试官追问一句“当前这个故障你判断是哪一种”,你很可能答不到点子上。
如果把整个链路画成一条流水线:第一层是网关/参数校验,第二层是 Redis,第三层是多级缓存或数据库。三个问题的破坏面也不是同一个级别的:
- 穿透:数据在数据库里根本不存在,所以缓存永远存不住,每次请求都会穿透到数据库,相当于“无效回源”被高频放大。
- 击穿:数据真实存在,但只有一个热点 key 的缓存恰好失效了,一瞬间大量针对同一个 key 的并发请求同时涌向数据库。
- 雪崩:大量 key 在同一时间窗口同时失效,或者 Redis 整个不可用,所有本来该被挡住的读请求,一次性全部落地到数据库。
从“缓存 miss 的范围”来区分它们特别清晰:穿透是“无论缓存有没有,数据本身不存在”,击穿是“大量并发命中了同一个刚过期的 key”,雪崩是“一大批 key 或缓存整体不可用”。后两者虽然也和过期有关,但一个是局部瞬间压力,一个是整体容量风险。这个前提理顺了,后面你才能在不同方案之间做取舍,而不是生搬硬套。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 缓存穿透:缓存和数据库都“查无此数据”,为什么会被打穿
2.1 穿透的典型路径与危害
缓存穿透指的是查询一个在数据库里根本不存在的数据。假设我维护一个用户体系,用户 ID 从 10000 开始自增,这时候有人用一个不存在的 ID,比如 100000000,去查用户详情。缓存里自然没有这个 key,数据库里也没有这一行,查询结果就是空。
问题出在“空结果不会被缓存”上。正常的用户数据在第一次查询后会被写回 Redis,下次请求就能命中;但一个不存在的 ID 每次查询都是缓存 miss,于是每一次请求都会老老实实地落到数据库。如果只是偶尔有人手滑输入了错误 ID,数据库完全顶得住;但如果是恶意攻击者批量生成大量非法 ID 来遍历接口,或者业务代码有 bug,把某一类查询结果全部回源到数据库,那么数据库的 QPS 会在短时间内被无效查询打满,最终拖垮整个服务。
很多人会把穿透理解成一个“安全攻击”才有的话题,实际业务中也很常见。比如搜索商品时,用户搜索一个已经下架的商品 ID;订单详情里查一笔不属于当前用户的订单;运营系统后台批量核对一批失效数据。这些场景下系统不是被“攻击”,但它们同样是“缓存存不住结果的读请求”。
穿透的真正危害,不只是每一次查询多花了几毫秒,而是它是一种“放大效应”。数据库的连接数是有限的,每一次回源查询都要占用一个连接,如果缓存 miss 的比例太高,数据库的连接池线程会全部卡在这些无效查询上,真正有数据的正常请求反而没有连接可用,最后形成雪崩式的连锁故障。
