面试后端岗位,缓存三兄弟几乎是必考题。但奇怪的是,能准确说出三者区别的人寥寥无几。很多人背了答案,却依然在线上踩坑。今天我们就用三个连环问,把这层窗户纸彻底捅破。
第一问:什么是缓存穿透?你该怎么防?
缓存穿透,指的是查询一个数据库里根本不存在的数据。因为不存在,所以缓存永远不会命中,每次请求都打到数据库。如果有人恶意用不存在的ID高频攻击,数据库压力瞬间飙升。
典型场景:用户查询id=-1的商品,缓存里没有,数据库也没有。正常逻辑是查不到就不写缓存,于是每次请求都穿透到DB。
解决方案有三招:
第一,缓存空值。查不到也写个null进Redis,设个短过期时间,比如60秒。这样后续同样请求直接命中空值,不会打到DB。
第二,布隆过滤器。把所有可能存在的key提前放进布隆过滤器,请求先过过滤器,不存在直接返回。优点是内存占用小,缺点是有误判率,且删除困难。
第三,参数校验。在入口层就拦截非法请求,比如ID必须为正整数、长度固定。这招最基础,但最容易被忽略。
第二问:什么是缓存雪崩?和穿透有什么区别?
缓存雪崩,指的是大量缓存同时失效,导致所有请求瞬间涌向数据库。注意,穿透是查不存在的数据,雪崩是查存在的数据,但缓存集体过期了。
常见原因:系统启动时批量加载缓存,设置了相同的过期时间;或者Redis集群宕机,整个缓存层不可用。
解决方案:
第一,过期时间加随机值。比如基础过期时间30分钟,再加个0到5分钟的随机偏移,避免同一时刻集体失效。
第二,多级缓存。本地缓存(Caffeine)+ Redis,即使Redis挂了,本地还能扛一阵。
第三,熔断降级。当数据库压力过大时,直接返回兜底数据或友好提示,别让DB崩掉。
第四,Redis高可用。主从+哨兵或集群模式,避免单点故障。
第三问:什么是缓存击穿?它和雪崩又差在哪?
缓存击穿,指的是某个热点key突然失效,大量请求同时涌向数据库。注意,是一个key,不是大批key。比如秒杀商品,缓存刚好过期,瞬间几千请求打到DB。
雪崩是“大面积失效”,击穿是“单点失效”。击穿往往发生在高并发场景下,破坏力极强。
解决方案:
第一,互斥锁。只让一个线程去查DB并重建缓存,其他线程等待。可以用Redis的SETNX实现分布式锁,或者用本地锁。伪代码:
if (缓存不存在) { if (获取锁成功) { 查DB,写缓存,释放锁 } else { 休眠50ms,重试 } }第二,热点数据永不过期。逻辑过期,后台异步更新。但实现复杂,适合极端热点。
第三,提前预热。秒杀开始前,手动把热点key加载进缓存,并设置较长过期时间。
三连问总结:一张表分清三者
| 问题 | 核心特征 | 数据是否存在 | 影响范围 | 核心解法 |
|---|---|---|---|---|
| 穿透 | 查不存在的数据 | 不存在 | 单key高频 | 空值缓存、布隆过滤器 |
| 雪崩 | 大量key同时失效 | 存在 | 大面积 | 随机过期、多级缓存、熔断 |
| 击穿 | 热点key失效 | 存在 | 单key高并发 | 互斥锁、永不过期、预热 |
最后一句
缓存三兄弟,本质都是请求绕过缓存直接打到数据库。区别在于触发条件和影响范围。面试时能说清区别,工作中能选对方案,才算真正掌握了。下次再被问到,别只背定义,把场景和取舍讲出来,你就赢了大多数人。