在分布式系统和高并发场景下,Redis 作为缓存层几乎是标配。但在使用过程中,经常会遇到 缓存穿透、缓存击穿、缓存雪崩 这三类典型问题。本文将对这三大问题进行深入解析,并介绍布隆过滤器在防止缓存穿透中的应用。
一、缓存穿透(Cache Penetration)
1. 问题描述
-
缓存穿透:请求的数据既不在缓存中,也不在数据库中。
-
每次请求都会绕过缓存,直达数据库,数据库压力持续升高。
-
典型情况:恶意攻击者不断请求不存在的
userId
,导致数据库被拖垮。
2. 解决方案
-
缓存空对象
- 如果数据库查不到数据,也把"空结果"写入 Redis,设置一个短 TTL。
-
布隆过滤器
-
在缓存前加一层布隆过滤器,判断 Key 是否可能存在。
-
如果布隆过滤器判定"不存在",直接返回,避免访问数据库。
-
-
接口限流 & 黑名单
- 对恶意请求的 IP/参数做限流。
二、缓存击穿(Cache Breakdown)
1. 问题描述
-
缓存击穿:某个热点 Key 突然过期。
-
此时有大量并发请求访问该 Key,在缓存失效的一瞬间,全都打到数据库。
-
典型场景:秒杀系统里的商品详情页。
2. 解决方案
-
互斥锁(Mutex)
- 只允许一个请求去加载数据库,其它请求等待。
-
逻辑过期
- 数据设置逻辑过期时间,过期后先返回旧数据,同时后台异步刷新缓存。
-
热点数据不过期
- 热点数据永不过期,定时任务主动更新。
三、缓存雪崩(Cache Avalanche)
1. 问题描述
-
缓存雪崩:大量 Key 在同一时间集中过期,或者 Redis 故障宕机。
-
结果:大规模缓存失效,数据库瞬间被海量请求压垮。
-
典型场景:秒杀活动开始,所有商品缓存都在同一时间过期。
2. 解决方案
-
随机过期时间
- 在 TTL 上加随机值,避免大规模同时过期。
-
缓存预热
- 系统启动时提前加载热点数据,防止冷启动时直接打 DB。
-
多级缓存
- 本地缓存(Guava、Caffeine)+ Redis 双层缓存,提升容灾能力。
-
限流 & 熔断
- 保护数据库,避免雪崩导致宕机。
四、布隆过滤器(Bloom Filter)详解
1. 定义
布隆过滤器是一种高效的 集合判断数据结构,用来判断某个元素是否"可能存在"。
-
优点:内存占用小,查询速度快。
-
缺点:存在少量误判(可能存在但实际上不存在),但不会漏判。
2. 工作原理
-
初始化一个位数组(Bit Array),全置 0。
-
插入元素时,用多个哈希函数计算位置,将对应位设为 1。
-
查询时,重新计算哈希:
-
如果某个位是 0 → 一定不存在。
-
如果所有位是 1 → 可能存在(有误判概率)。
-
3. 在缓存中的作用
-
防止缓存穿透
-
将数据库中所有合法 Key 预先加入布隆过滤器。
-
当请求到来时,先查询布隆过滤器:
-
不存在 → 直接拦截,不访问缓存和数据库。
-
可能存在 → 继续走缓存/数据库流程。
-
-
五、三大问题对比总结
问题 | 出现场景 | 特点 | 影响 | 解决方案 |
---|---|---|---|---|
穿透 | 查询缓存和数据库都不存在的数据 | 永远不命中缓存 | 数据库持续高压,可能被攻击利用 | 缓存空值、布隆过滤器、限流 |
击穿 | 某个热点 Key 突然过期 | 单个热点 Key 瞬时失效 | 大量请求打到数据库 | 加锁、逻辑过期、热点 Key 不过期 |
雪崩 | 大量 Key 同时过期或 Redis 宕机 | 批量缓存失效 | 数据库被瞬时压垮 | 随机 TTL、预热、多级缓存、限流 |
六、总结
Redis 缓存虽然能大幅提升系统性能,但如果不注意设计,很容易因为 穿透、击穿、雪崩 造成数据库压力暴增。
-
穿透 → 布隆过滤器/缓存空值
-
击穿 → 加锁/逻辑过期
-
雪崩 → 随机过期/预热/多级缓存
同时,布隆过滤器是解决缓存穿透的利器,在大规模高并发场景中尤为重要。