Redis中缓存的穿透,击穿,雪崩
1. 缓存穿透
现象: 指查询一个根本不存在的数据。缓存中没有,数据库中也没有。由于数据库里查不到,也就没法写回缓存,导致每次请求这个“不存在”的数据都要去冲击数据库。
- 诱因: 恶意攻击(故意查询不存在的 ID)或业务逻辑失误。
- 后果: 数据库压力激增,甚至崩溃。
解决方案:
- 布隆过滤器 (Bloom Filter): 在缓存之前增加一个屏障,记录所有可能存在的 Key。如果布隆过滤器判断 Key 不存在,直接返回,不查询数据库。
- 缓存空对象: 如果数据库返回空,也把这个
null结果写进缓存,但设置一个较短的过期时间(如 5 分钟),防止同一 Key 持续攻击。
2. 缓存击穿
现象: 指一个热点 Key(比如微博热搜、秒杀商品)在过期的瞬间,有海量请求同时涌入。
这个 Key 此时在缓存中失效了,所有请求会同时打到数据库去尝试加载数据并回写缓存。
- 特点: 针对“单一”热点数据。
- 后果: 数据库瞬时负载过高,甚至卡死。
解决方案:
- 设置逻辑过期: 不给 Key 设置物理过期时间,而在 Value 中存储一个过期字段。发现逻辑过期后,后台异步更新。
- 互斥锁 (Mutex Lock): 只有获得锁的那个线程能去查数据库并写缓存,其他线程等待或重试,确保数据库只被查一次。
3. 缓存雪崩
现象: 指在同一时段,大量的缓存 Key 同时失效,或者 Redis 服务宕机。
原本由缓存承担的请求全部涌向数据库。
- 区别: 击穿是“点”,雪崩是“面”。
- 后果: 数据库发生连锁反应,整个系统直接瘫痪。
解决方案:
- 过期时间加随机偏移: 为每个 Key 的过期时间加上一个随机数(如 1-5 分钟),防止 Key 集体同时到期。
- 搭建高可用集群: 使用 Redis Sentinel(哨兵)或 Redis Cluster 避免单点故障。
- 熔断与限流: 如果数据库压力过大,直接触发熔断,返回友好提示,保护底层数据库不被压垮。
4.布隆过滤器
专门用于判断一个元素是否在一个集合中。用极小的内存,换取极快的查询速度,但是会牺牲一点准确性。
在解决缓存击穿的问题中,布隆过滤器位于请求到达Redis之前,对于key查得到就放行,否则直接返回
布隆过滤器的底层是一个 位数组(初始全为0) 和一组哈希函数。
写入过程:
- 当一个 Key(如
user:123)进入时,会通过 k 个不同的哈希函数计算出 k 个哈希值。 - 将位数组中这 k 个哈希值对应位置的 0 改为 1。
查询过程:
- 对要查询的 Key 进行同样的 k 次哈希计算。
- 查看位数组中对应的 k 个位置。
- 结果判定:
- 只要有任意一个位置是 0,说明该 Key 肯定没被存过
- 如果所有位置都是 1,说明该 Key 可能被存过
1 | import org.redisson.api.RBloomFilter; |
核心区别对比
| 问题 | 触发原因 | 涉及数据 | 重点对策 |
|---|---|---|---|
| 穿透 | 数据压根不存在 | 非法/不存在的数据 | 布隆过滤器、缓存空值 |
| 击穿 | 热点 Key 到期 | 单个极热点数据 | 互斥锁、逻辑不过期 |
| 雪崩 | 批量 Key 到期或服务掉线 | 广范围的数据 | 随机过期时间、高可用集群 |
Comments