【避坑指南】Redis缓存三大经典问题
Redis 缓存三大经典问题:击穿、穿透、雪崩
在高并发系统中,Redis 作为高性能缓存层,常面临三大典型问题:缓存击穿、缓存穿透、缓存雪崩。它们虽名称相似,但成因、影响范围、解决方案完全不同。
仍然是先来一张图缓解压力

一、缓存击穿(Cache Breakdown)—— 热点 Key 失效
问题定义
当大量请求同时访问一个热点 key,而该 key 恰好在过期瞬间失效,导致所有并发请求直接穿透到数据库,造成瞬时高负载,甚至压垮数据库。
核心特征:1. 单个 key 失效。2. 并发量极高。3. 数据库压力集中爆发
解决方案
1. 互斥锁(Mutex Lock)
在发现缓存失效后,通过分布式锁(如 Redis 的 SETNX)保证只有一个请求去查询 DB,其他请求等待或重试。 其优点是保证数据一致性,避免重复查询 DB。而缺点就是增加延迟;锁竞争可能成为瓶颈;需处理锁释放失败
2. 逻辑过期(Logical Expiration)
在缓存中不依赖 Redis TTL,而是存储一个逻辑过期时间戳(作为一个字段存储在value里)。当请求发现“逻辑过期”,线程异步更新缓存,当前请求仍返回旧数据。优点是无锁、无阻塞、用户体验好。缺点就是可能数据短暂不一致;需确保异步任务可靠执行
1 | |
3. 永不失效 + 后台刷新
对已知热点 key,设置超长 TTL 或永不过期,并通过后台定时任务主动刷新缓存。 优点是彻底避免击穿,缺点是需维护后台任务;若数据变更频繁,可能不及时
1 | |
二、缓存穿透(Cache Penetration)—— 无效访问 / 不存在的 Key
问题定义
大量请求访问根本不存在于数据库和 Redis 的 key(如恶意爬虫、参数错误),导致每次请求都穿透到数据库,造成数据库压力过大。 其核心特征有:1. key 不存在。2. 请求反复发生。3. 数据库持续被无效查询
解决方案
1. 布隆过滤器(Bloom Filter)
具体来说,我们在缓存前加一层布隆过滤器,快速判断 key 是否“可能存在”。若返回“不存在”,则直接拒绝请求,不查缓存也不查 DB。 那么这种方法的优点在于内存占用小、查询极快(O(1))、有效拦截无效请求。而缺点是存在误判率(可能把存在的 key 判为不存在),但不会漏判。
适用场景:数据集合相对固定、可预加载(如用户 ID、商品 ID)
2. 缓存空值(Null Cache)
查询 DB 为空时,仍将空结果写入缓存,并设置较短 TTL(如 60s),防止重复穿透。 优点:简单有效,拦截重复无效请求。缺点:占用内存;需防范恶意构造大量不存在 key
3. 拒绝无效访问(请求校验 + 限流)
对请求参数做合法性校验(如 ID > 0),并对高频无效请求进行IP 限流或黑名单。
三、缓存雪崩(Cache Avalanche)—— 缓存集体失效
问题定义
大量缓存在同一时刻集中过期,或 Redis 服务宕机,导致所有请求直接打到数据库,造成数据库压力过大甚至崩溃。
核心特征:1. 大面积失效 2. 全局性灾难。3. 数据库承受洪峰流量
解决方案
1. TTL 随机化(过期时间打散)
在基础 TTL 上增加随机偏移,避免集体过期。 缺点是无法解决Redis服务器宕机的问题
2. 服务高可用(哨兵 / 集群)
部署 Redis 主从 + 哨兵 或 Redis Cluster,避免单点故障。
3. 多级缓存(本地缓存 + Redis)
应用层加 本地缓存(如 Caffeine、Guava Cache),即使 Redis 宕机,本地缓存仍可支撑部分请求。 优点:提升容灾能力,降低 Redis 依赖。缺点:存在缓存一致性问题(需配合失效机制)
4. 熔断降级 + 限流
使用 Hystrix、Sentinel 等组件,在 DB 压力过大时:
- 熔断:直接返回默认值或错误。
- 限流:拒绝部分请求,保护 DB。
总结对比表
| 问题类型 | 触发原因 | 核心思想 | 解决方案 |
|---|---|---|---|
| 缓存击穿 | 热点 key 过期 | 保护单点 | 互斥锁 / 逻辑过期 / 永不过期 |
| 缓存穿透 | 查询不存在 key | 拦截无效请求 | 布隆过滤器 + 空值缓存 + 参数校验 |
| 缓存雪崩 | 大量 key 同时过期 / Redis 宕机 | 分散风险 | TTL 随机化 + 高可用 + 多级缓存 |