Java 面试题

缓存穿透、击穿、雪崩:Redis三大经典问题

"缓存穿透、缓存击穿、缓存雪崩分别是什么?怎么解决?"

为什么面试官会问这道题

这三个场景是缓存的经典失效模式,后端面试几乎必问。考察你能不能预见攻击模式和流量尖峰——是真的设计过缓存系统,还是只背过概念。

如何回答

  1. 1

    先把三个概念讲清楚——穿透:查询缓存和DB都不存在的数据,缓存永远填不上,每次都打DB。击穿:某个热点key刚好过期,大量并发请求同时打到DB。雪崩:大量key同时过期(或Redis本身挂了),DB被打爆。

  2. 2

    穿透解法:缓存空值短过期时间,或者在缓存前加布隆过滤器,已知不存在的key直接拒绝,连Redis都不用查。

  3. 3

    击穿解法:用互斥锁(SETNX),只允许一个线程去DB重建缓存,其他线程等待或返回旧值;或者热key设"逻辑永不过期",后台异步刷新。

  4. 4

    雪崩解法:TTL加随机抖动(基础TTL + 随机偏移)避免同时过期;加本地多级缓存(Caffeine + Redis);DB侧加熔断和限流;Redis本身做高可用(哨兵/集群)防止缓存层整体崩溃。

  5. 5

    串联总结:生产环境是多层防御——布隆过滤器+空值缓存防穿透、互斥锁防击穿、TTL抖动+本地缓存+熔断防雪崩。

参考回答示例

这三个是不同的失效模式。缓存穿透是查询既不在缓存也不在DB的数据,比如攻击者不停请求/user/-1,缓存永远填不上,每次都打DB。两种防御:把null结果也缓存起来,设短TTL(比如60秒),重复攻击直接被Redis拦住;或者前置布隆过滤器,启动或写入时把所有有效ID加到过滤器里,查询前先过一遍,不存在直接拒绝。布隆过滤器会有误判(把不存在说成存在),但绝不会漏判,所以用来挡穿透是安全的。缓存击穿是数据本来存在,但某个热点key刚好过期,还没来得及重建,几千个并发请求全部打到DB。解法一是互斥锁——第一个miss的请求去抢一个短TTL的Redis锁,抢到的去重建,其他的等待或返回旧值;解法二是"逻辑永不过期",实际TTL不设,但value里带一个逻辑过期时间戳,读到过期就异步触发后台重建,其他请求继续读老数据。缓存雪崩是大量key同时过期,或者Redis整个挂了,全量读流量冲到DB把它打爆。防御是多层的:第一,TTL加抖动——别给所有key设相同的3600秒,而是3600 + random(0, 600),过期时间打散。第二,加本地进程内缓存(Java里用Caffeine),Redis挂了每个JVM还能靠自己的内存扛一分钟。第三,DB前加熔断和限流,DB扛不住时快速失败而不是堆积连接拖死整个系统。第四,Redis本身上Sentinel或Cluster,避免单点挂掉缓存层直接蒸发。生产环境我会把这些组合起来:布隆过滤器+空值缓存+TTL抖动+本地缓存+熔断,而不是只选一个。

实用技巧

  • 面试官常把三个搞混,先清晰定义再讲解法。

  • 能讲出布隆过滤器和它的误判特性,是加分项。

  • 雪崩场景必须"TTL抖动+本地缓存+熔断"三层一起上,单独讲一个都不完整。

  • 真实面试容易把击穿和雪崩说反,即答侠可以帮你临场确认用词。

常见问题

缓存空值有什么代价?

占Redis内存——尤其被大量攻击时。用短TTL(60秒)和紧凑的空标记(空字符串)控制成本。

重建缓存的互斥锁怎么实现?

SET mutex:keyname 1 NX PX 30000。抢到的线程去DB重建,其他线程短暂sleep后重试。

缓存预热能避免雪崩吗?

预热只对启动/发布后有效,不能防批量TTL同时到期。预热要配合TTL抖动才完整。

面试时担心忘词?即答侠实时助你

即答侠 AI 实时监听面试对话,自动识别问题并即时生成回答建议——无感辅助,让你从容应对每一道题。

免费试用即答侠