问题: 请分别定义缓存穿透、缓存击穿、缓存雪崩,并针对每种问题给出至少两种解决方案(如布隆过滤器、互斥锁、随机过期时间等)

👇 点击展开/折叠 面试背诵模板(建议先背这个) 缓存穿透指查询不存在的数据,缓存层和存储层均未命中,导致请求直达数据库,可能被恶意攻击压垮。解决方案:布隆过滤器预判key是否存在;缓存空值(null)并设置短过期时间。缓存击穿指热点key在失效瞬间,大量并发请求穿透缓存直达数据库。解决方案:互斥锁(SETNX)确保单线程重建缓存;逻辑过期(不设物理过期,异步刷新)避免锁等待。缓存雪崩指大量key同时失效或缓存节点宕机,导致大量请求涌入数据库。解决方案:过期时间增加随机偏移量,避免集体失效;搭建高可用集群(主从+哨兵/Cluster);实施熔断降级与限流兜底。
---

一、缓存穿透(Cache Penetration)

定义:查询一个不存在于缓存和数据库中的key,每次请求都绕过缓存直达数据库,造成数据库压力剧增,常被恶意攻击利用(如查询不存在的用户ID)。

解决方案:

① 布隆过滤器(Bloom Filter):在缓存层前置一个布隆过滤器,存储所有可能存在的数据key。查询时先经过布隆过滤器判断key是否存在,若不存在则直接返回,不访问数据库。注意布隆过滤器存在误判率(假阳性),需根据业务容忍度调整哈希函数数量和位图大小。

② 缓存空值(Cache Null Value):当数据库查询返回空结果时,仍将该key存入缓存,value设为null并设置较短的过期时间(如5分钟)。此方案简单有效,但需注意大量空值key占用内存,适合攻击key数量有限的场景。


二、缓存击穿(Cache Breakdown)

定义:某个高频访问的热点key在缓存过期失效的瞬间,大量并发请求同时发现缓存失效,全部穿透到数据库,造成数据库瞬时压力激增。

解决方案:

① 互斥锁(Mutex Lock):使用Redis的SETNX命令,仅允许一个线程/进程去数据库重建缓存,其他线程等待或轮询。重建完成后释放锁,其他线程直接从缓存读取。关键点:设置锁的过期时间(防止重建线程意外崩溃导致死锁),且锁的value需唯一标识(防止误删)。

② 逻辑过期(Logical Expiration):缓存中不设置物理过期时间(TTL),而是在value中存入一个逻辑过期时间字段。读取时若发现逻辑过期,异步线程去数据库刷新缓存,当前请求仍返回旧数据。此方案无需等待锁,响应快,但数据短暂不一致,适合对实时性要求不高的场景。


三、缓存雪崩(Cache Avalanche)

定义:缓存中大量key在同一时间段集中过期,或缓存服务节点整体宕机,导致大量请求同时绕过缓存直接打到数据库,引发数据库过载甚至宕机。

解决方案:

① 随机过期时间(Random TTL):为每个key设置过期时间时,在基础时间上增加一个随机偏移量(如基础时间 + 随机0~300秒),避免大量key在同一时刻集体失效。

② 高可用集群部署:使用Redis主从+哨兵模式或Redis Cluster,避免单节点故障导致整个缓存不可用。同时配置多级缓存(如本地缓存Ehcache + Redis),即使Redis宕机,本地缓存仍能兜底部分流量。

③ 熔断降级与限流:当数据库访问延迟升高或错误率激增时,触发熔断机制(如Hystrix),快速失败返回默认值或友好提示;同时限制每秒通过的请求数(限流),保护数据库不被瞬时流量冲垮。


四、三种异常对比总结

问题 根本原因 危害特征 核心解决方向
缓存穿透 查询不存在的数据 恶意攻击,大量请求直达DB 前置过滤(布隆过滤器)或空值缓存
缓存击穿 单个热点key瞬间失效 瞬时高并发穿透 互斥锁重建或异步逻辑过期
缓存雪崩 大量key同时失效/节点宕机 流量洪峰压垮DB 分散失效时间 + 高可用架构 + 限流熔断