NiceOffer

八股文解析

Redis 缓存穿透/击穿/雪崩有什么区别?怎么防?

Redis八股文缓存

一句话结论

缓存穿透查不存在的数据打穿DB,缓存击穿热点key过期瞬间打爆DB,缓存雪崩大量key同时失效导致DB整体崩溃,三者本质是缓存未命中后的DB保护问题。

面试标准答法

1. 缓存穿透(Cache Penetration)

定义:查询一个根本不存在的数据,缓存和数据库都没有,每次请求都直接打到数据库。

关键机制

  • 请求流程:Client → Redis(未命中) → MySQL(无记录) → 返回null
  • 恶意攻击场景:攻击者构造大量不存在的ID(如负数、UUID、超范围ID)持续请求
  • 危害:DB 承受大量无效查询,连接池耗尽,服务雪崩

核心解决方案

方案原理代价
缓存空值(Null Cache)将null结果也缓存,TTL设短(30-60s)额外内存,需防大量key堆积
布隆过滤器(Bloom Filter)请求前先判断key是否可能存在,不存在直接拒绝有误判率(false positive),需维护全量数据
参数校验拦截非法参数(如id<=0)只防低级攻击,防不住合法格式的无效key

关键参数:布隆过滤器误判率默认设置 0.01,位数组大小 m = -n*ln(p)/(ln2)^2,哈希函数个数 k = m/n * ln2

2. 缓存击穿(Cache Breakdown / Hotspot Key Expiration)

定义单个热点key 在缓存过期的瞬间,大量并发请求同时穿透到数据库。

关键机制

  • 触发条件:热点key(如秒杀商品、微博热搜)过期 + 高并发访问
  • 时间窗口:key过期后到新值回填前的极短时间窗口内,所有请求直击DB
  • 与穿透区别:穿透是查不存在的数据,击穿是查存在但缓存刚好过期的数据

核心解决方案

方案原理适用场景
互斥锁(Mutex Lock)缓存未命中时,只放一个线程去查DB,其他线程等待/自旋并发量极大,一致性要求高
逻辑过期(Logical Expiration)缓存中存 value + expireTime,线程发现逻辑过期后异步刷新允许短暂脏读,追求极致性能
热点key永不过期 + 后台定时刷新物理上不设TTL,由Job定期更新数据变更频率可控

互斥锁实现要点:使用 SETNX(SET if Not eXists)加锁,设置合理超时时间(如200ms),防止死锁;等待线程需设置最大等待时间,避免无限阻塞。

3. 缓存雪崩(Cache Avalanche)

定义大量key同时失效(或Redis集群宕机),导致所有请求全部打到数据库,DB瞬间被压垮。

关键机制

  • 两种触发场景:① 大量key设置了相同的过期时间(如零点统一过期) ② Redis集群故障(主从全挂)
  • 雪崩是击穿的大规模版本:击穿是单点失效,雪崩是批量失效

核心解决方案

方案原理缺点
过期时间加随机值TTL = 基础值 + random(0, 300s)简单有效,防同时失效
多级缓存(L1+L2)本地缓存(Caffeine/Guava)+ Redis,本地缓存抗住第一波需维护一致性
Redis高可用主从 + 哨兵(Sentinel)/ 集群(Cluster),自动故障转移增加运维复杂度
服务降级 + 限流Hystrix/Sentinel 熔断降级,返回兜底数据业务需接受降级响应

对比总表

维度穿透击穿雪崩
核心问题数据不存在单个热点key过期大量key同时过期/Redis宕机
并发特征持续低频/恶意高频瞬时超高并发瞬时全量请求
数据状态缓存和DB都没有DB有,缓存没有DB有,缓存批量没有
首要解决方案布隆过滤器/空值缓存互斥锁/逻辑过期TTL随机化/高可用
影响范围单key无效查询单key热点全局/大面积
检测方式缓存命中率骤降单个key QPS突增整体缓存命中率暴跌

常见追问

追问回答要点
布隆过滤器支持删除吗?标准布隆过滤器不支持删除(每个bit可能被多个元素共享)。如需删除用计数布隆过滤器(Counting Bloom Filter),每个槽位用计数器代替bit。
互斥锁方案中,其他线程等待多久?推荐自旋 + 超时:自旋间隔50ms,最大等待500ms(DB查询平均耗时)。超时后返回默认值或降级数据,避免线程堆积。
缓存空值的TTL设多少合适?30-60s。太短防不住穿透,太长会导致数据更新后长时间不可见。可配合异步更新:发现key被写入后主动删除空值缓存。
Redis集群宕机怎么办?① 依赖多级缓存(本地缓存兜底) ② 开启持久化(RDB/AOF)快速恢复 ③ 触发熔断降级,直接返回静态数据或错误码,保护DB。

面试回答模板(30秒版)

延伸准备(加分项)

  1. 缓存一致性深挖:穿透/击穿/雪崩的防护方案与缓存一致性(Cache Aside Pattern、Write Behind)的冲突点。例如逻辑过期方案会牺牲一致性,如何用版本号binlog订阅(Canal)补偿。
  1. 热点key的自动发现:生产环境如何自动识别热点key?基于Redis的hotkey分析redis-cli --hotkeys)、JD本地统计代理层(Codis/Twemproxy)流量分析。知道这个说明你有实战经验。
  1. 布隆过滤器的工程落地:数据量100亿级别时,布隆过滤器初始化需要扫描全量数据,如何用分段构建 + 渐进式加载避免启动阻塞?误判率如何动态调整?能讲清楚这些细节会明显加分。

想系统备战大厂大模型/Agent 开发?NiceOffer 提供 SDE+LLM 双轨 1v1 陪跑,合同保底 40w 年薪,文末扫码咨询。