
Redis缓存穿透、击穿、雪崩面试答不上怎么办?5个扣分点把排查路径讲清
这篇文章把 Redis 缓存穿透、击穿、雪崩拆成可判断的故障范围,并给出回源控制、TTL 设计、监控验证和面试话术清单。
先记住这段 30 秒答法
面试官问「Redis 缓存穿透、击穿、雪崩」,通常不是要你把三个定义背完,而是想看你能不能先判断故障范围,再选择保护数据库的动作。
可以先这样回答:
缓存穿透是缓存和数据库里都没有这个数据,请求反复查库;缓存击穿是某个热点 key 失效后,大量并发请求同时回源;缓存雪崩是大量 key 集中过期,或者缓存整体不可用,导致大批请求回源。我的处理顺序是:先做参数校验和空值保护,再针对热点 key 做互斥加载或逻辑过期,对批量过期做 TTL 抖动、预热、限流和降级。最后用缓存命中率、回源 QPS、数据库连接池和接口延迟验证方案是否真的生效。
这段话的重点不在于术语多,而在于你已经给出了三个判断维度:数据是否存在、受影响的是一个 key 还是一批 key、数据库能不能安全地接住回源流量。
先分清三种故障
在常见的旁路缓存路径里,应用先查缓存;命中就返回,未命中才查数据库并把结果写回缓存。Redis 官方把 cache-aside 视为常见的缓存方式,AWS 的说明也把这条读路径拆成了 cache hit、cache miss、查库和回填四步。12
因此,三类问题其实都是「未命中之后发生了什么」:
| 问题 | 数据状态 | 典型范围 | 面试时先说什么 |
|---|---|---|---|
| 缓存穿透 | 缓存没有,数据库也没有 | 大量不存在或非法 key | 先拦参数、缓存空值,必要时用布隆过滤器 |
| 缓存击穿 | 数据库有,但热点 key 在缓存中失效 | 一个或少数热点 key | 让同一个 key 同时只有一个请求回源 |
| 缓存雪崩 | 大量 key 同时失效,或缓存整体不可用 | 一批 key,甚至整个缓存层 | 错开过期时间,并限制回源流量 |
这三种叫法在不同团队里可能有轻微差异。面试时不要纠结术语边界,直接补一句「我按影响范围来区分」,比和面试官争定义更稳。三类问题的常用区分和处理方向,可参考腾讯云对 Redis 缓存问题的整理。3
第 1 个扣分点:只背定义,不先问数据状态
看到「缓存 miss」就直接说「查数据库」,这是最容易被追问的地方。你要先问两个问题:
- 这个 key 对应的数据在数据库里是否存在?
- 这是一个热点 key,还是大量 key 同时 miss?
如果数据根本不存在,反复回源只会让数据库重复做无效查询,这是缓存穿透。准备时可以把方案分成三层:
- 请求入口校验:例如主键必须是正整数、枚举值必须在允许范围内。明显非法的参数不进入缓存和数据库。
- 缓存空结果:数据库确认「不存在」后,缓存一个明确的空值标记,并设置明显短于正常数据的 TTL。不要把数据库超时、网络异常或权限错误也缓存成「不存在」。
- 布隆过滤器:当 key 集合相对稳定且规模较大时,可以先过滤掉确定不存在的 key。它适合做前置拦截,不应被表述成绝对准确的数据库替代品。3
面试话术可以这样收束:
如果是明显非法参数,我会在接口层拦截;如果是合法但不存在的数据,我会缓存短 TTL 的空值,避免同一个不存在的 key 持续查库。布隆过滤器是否引入,要看 key 集合是否稳定、更新链路是否可靠,以及误判带来的回源成本。
这里的取舍也要说出来:空值 TTL 太长会让新创建的数据短时间不可见,太短又挡不住持续攻击;布隆过滤器需要维护数据集合,不能只说「加一个就好了」。
第 2 个扣分点:把击穿和雪崩混成一个词
区分它们最简单的办法是看失效数量:
- 击穿看一个热点 key。例如一个热门商品详情刚好过期,大量请求同时发现 miss。如果每个请求都去查库,就会出现瞬时回源峰值。
- 雪崩看一批 key 或整个缓存层。例如批量写入时给大量 key 设置了相同 TTL,到了同一时间集中失效;也可能是缓存服务故障,让原本由缓存承接的请求全部转向数据库。
Redis 的
EXPIRE 会给 key 设置过期时间,超时后自动删除;TTL 可以查看剩余生存时间。4 所以,TTL 不是随手填一个固定数字就结束了。批量生成缓存时,可以在基础 TTL 上加入受控的随机抖动,让 key 不要在同一秒集中失效;热点数据还可以在高峰前预热,或者采用后台刷新与可接受的短暂旧值。两类问题对应的回答不能一样:
热点 key 击穿:控制同一个 key 的回源并发
一个可复述的处理流程是:
- 先查缓存,命中直接返回。
- miss 后尝试获取这个 key 对应的互斥控制权。
- 只有拿到控制权的请求查询数据库并回填缓存。
- 其他请求短暂等待后重查缓存;等待超过上限,就返回降级结果或明确的可重试响应。
另一种思路是逻辑过期:缓存内容和过期时间分开,读到过期标记时先返回仍可接受的旧值,再异步刷新。它降低了热点 key 的同步回源压力,但会引入数据新鲜度问题,商品价格、库存、权限等场景不能不加判断地套用。
批量 key 雪崩:降低同时回源的概率和规模
回答至少要覆盖三道防线:
- 提前错开:TTL 加抖动,批量任务分批预热,不让所有 key 使用同一个过期时刻。
- 限制回源:对数据库查询做并发上限、队列或限流,避免缓存失效时把数据库连接池打满。
- 准备降级:明确哪些数据可以返回旧值、默认值或稍后重试,哪些请求必须失败,避免「数据库已经过载,服务还在无限重试」。
「热点 key 用互斥加载,批量失效用错峰和限流」这句比「三种问题都加分布式锁」更有辨识度。
第 3 个扣分点:只会说「加锁」
锁不是答案本身,锁的范围、等待方式和失败后的动作才是答案。
当你说「用分布式锁解决击穿」,面试官很可能继续问:
- 锁是按整个缓存服务加,还是按热点 key 加?
- 拿到锁的请求查库失败,其他请求等多久?
- 持锁线程异常退出,锁如何自动释放?
- 数据库慢查询时,等待请求会不会一起堆积?
- 这个方案是否真的需要跨实例协调,还是单机 single-flight 就够?
可以按下面四句话回答:
锁粒度按 key 控制,避免不同商品相互阻塞。持锁请求负责一次回源和回填,锁必须有超时,避免异常退出后永久占用。未拿到锁的请求只做有限次数重试,超过预算就走降级。流量很小或只有单实例时,我不会为了背概念强行引入分布式锁。
如果项目里没有真正做过锁,不要编造锁超时时间、QPS 或故障数据。把「我们线上用了」改成「我的设计会这样处理」,并明确哪些部分还需要压测验证。
第 4 个扣分点:只讲防护,不讲怎么验证
「加了 TTL 抖动」「用了布隆过滤器」「加了锁」都不是结果。你要说明上线后看什么。
Redis
INFO 的 stats 部分提供 keyspace_hits 和 keyspace_misses,分别表示 key 查找成功和失败的次数,可以据此观察命中与未命中趋势。5 面试中可以按这张清单回答:| 观察项 | 你要确认的问题 |
|---|---|
| 缓存命中率 | 失效后是否出现异常下降,是否只集中在某个业务 key 前缀 |
| 回源 QPS | miss 增加后,数据库查询是否同步放大 |
| 热点 key 分布 | 是单个 key 的访问集中,还是大量 key 一起过期 |
| 锁等待与回源耗时 | 是否只有一个请求查库,等待请求是否超出接口预算 |
| 数据库连接池、CPU、P95/P99 | 保护措施有没有把压力转移成排队和长尾 |
Redis 的
SLOWLOG 会记录超过配置执行时间阈值的命令,但它不包含与客户端通信的网络 I/O 时间,所以不能只看慢日志就判断端到端延迟。6一段更像真实排查的回答是:
我会先按 key 前缀和时间窗口看命中率、miss 数和回源 QPS,再对照数据库连接池和接口 P99。如果只有一个热点 key 的 miss 突增,我优先查互斥加载和热点访问;如果多个前缀同时下降,我会查批量任务、TTL 分布和缓存实例健康。Redis 慢日志只能说明命令执行阶段,网络和应用排队要看链路指标。
第 5 个扣分点:没有自己的项目证据
技术题最后常常会回到你的简历:「你项目里真的遇到过吗?」
准备一条真实经历时,用下面五个空格填,不要背网上的事故故事:
- 场景:哪个接口、什么数据、什么访问特点?
- 信号:先出现了命中率下降、回源增加、数据库长尾,还是错误率上升?
- 判断:为什么判断是穿透、击穿或雪崩,而不是 Redis 本身变慢?
- 动作:你改了入口校验、空值缓存、互斥加载、TTL、限流还是降级?
- 验证:用什么指标确认恢复,方案带来了什么新代价?
可直接替换的回答骨架如下,方括号里的内容必须换成你的真实经历:
在[业务接口]中,我们发现[具体时间窗口内的异常信号]。我先按 key 维度看缓存 miss 和回源 QPS,判断这是[一个热点 key / 多个 key 集中过期 / 大量不存在 key]。随后采用[具体措施],把回源并发控制在[真实约束],并通过[真实监控指标]验证。这个方案的代价是[旧值可能短暂不新鲜 / 增加了锁等待 / 需要维护过滤器],所以只用于[明确业务范围]。
如果你只有本地练习,没有线上事故,可以诚实地说「这是我的设计方案,尚未在线上验证」,然后补上压测计划。可信度来自边界和验证方式,不来自一个听起来很大的数字。
面试前一晚,按这 3 步练
1. 画出一条回源路径
在纸上写清:请求入口、缓存、数据库、回填、降级出口。然后分别标记「一个 key 失效」和「大量 key 失效」时,哪一段并发会放大。
2. 为每类问题选一个主方案
- 穿透:参数校验 + 空值短 TTL。
- 击穿:按 key 互斥加载,或可接受旧值时采用逻辑过期。
- 雪崩:TTL 抖动 + 分批预热 + 回源限流。
不要准备十个方案却说不清为什么选它。面试官更关心你的约束和取舍。
3. 让别人连续追问 5 次
至少练这五问:
- 为什么不把热点 key 设置成永不过期?
- 空值缓存会不会影响刚创建的数据?
- 锁拿不到时,所有请求都等着吗?
- Redis 挂了,数据库能不能接住流量?
- 你怎么证明方案生效,而不是只是错误变少了?
每个问题都用「前提、动作、代价、验证」四句话回答,直到不需要翻资料。
最后检查清单
在面试前,确认自己能做到:
- 用一句话区分穿透、击穿、雪崩,并说清数据是否存在和影响范围。
- 针对穿透说出参数校验、空值短 TTL,以及什么时候考虑布隆过滤器。
- 针对击穿说清按 key 控制回源并发,而不是笼统地说「加锁」。
- 针对雪崩说出 TTL 抖动、预热、限流和降级,并说明数据新鲜度取舍。
- 说出至少 3 个验证指标:命中率、回源 QPS、数据库连接池或端到端延迟。
- 准备一条真实项目经历,缺少线上数据时明确说是设计方案,不编数字。
관련 콘텐츠
- 로그인하면 댓글을 작성할 수 있습니다.
