redis常见问题及解决方案
1. 缓存穿透
问题
大量请求不存在的数据(如 id=-1、非法 id),缓存查不到,直接打穿到数据库,导致 DB 压力巨大甚至宕机。
解决方案
- 缓存空值查询 DB 无结果时,缓存
null或空对象,并设置短过期时间(如 30s)。 - 布隆过滤器(Bloom Filter)提前把存在的 key 存入布隆过滤器,请求先过过滤器,不存在直接返回,不查缓存和 DB。
- 接口层参数校验 + 限流拦截非法参数,防止恶意攻击。
2. 缓存击穿
问题
某个热点 key 过期瞬间,大量并发请求同时打到数据库。特点:单个 key 热点 + 过期。
解决方案
- 互斥锁(分布式锁)缓存不存在时,用
SETNX加锁,只允许一个线程去 DB 加载数据并更新缓存。 - 热点 key 永不过期逻辑过期:缓存中存过期时间,后台异步刷新,不直接删除 key。
- 随机过期时间避免同一时间大量 key 集中失效。
3. 缓存雪崩
问题
大量 key 同一时间集体过期或 Redis 宕机,所有请求直接涌入数据库,DB 被压垮。
解决方案
- 过期时间加随机值如
3600 + random(600),避免集中失效。 - 多级缓存Caffeine 本地缓存 + Redis 分布式缓存。
- Redis 高可用主从 + 哨兵 / Redis Cluster,避免单点故障。
- 服务降级、熔断、限流Redis 不可用时直接返回默认值,不查 DB。
- 互斥锁 + 预热提前加载热点数据,避免集中重建。
4. 缓存与数据库双写不一致
问题
更新 DB 与更新缓存顺序不当,导致脏数据、数据不一致。
解决方案
方案一:删除缓存,而不是更新缓存
- 写请求:先更新数据库,再删除缓存
- 读请求:命中缓存直接返回,未命中查 DB 并回填缓存
方案二:延迟双删
- 先删缓存
- 更新 DB
- 延迟几百 ms 再删缓存减少并发读写导致的短暂不一致。
方案三:最终一致性(可靠方案)
- 监听 binlog(Canal)异步更新缓存
- MQ 异步更新,保证最终一致
5. 缓存污染 / 大 key 问题
问题
- 存入超大 value(几 MB 甚至几十 MB)
- 网络 IO 阻塞、Redis 单线程卡顿、内存暴涨
解决方案
- 拆分大 key把大 hash/list 拆成多个小 key。
- 控制 value 大小避免存大文本、大图片。
- 定期清理冷数据设置合理过期,使用 LRU 淘汰策略。
- 使用压缩对大文本 gzip 压缩后存储。
6. 缓存并发竞争
问题
多个客户端同时修改同一个 key,导致执行顺序错乱。
解决方案
- 分布式锁(Redlock / Redisson)
- 使用Redis 事务 + watch
- 利用单线程特性,用 Lua 脚本保证原子性。
7. 缓存预热
问题
系统刚启动,缓存为空,流量直接打 DB。
解决方案
- 项目启动时异步加载热点数据
- 定时任务预热
- 手动触发缓存刷新
8. 缓存污染(冷数据占满内存)
问题
大量不常用数据进入缓存,挤掉热点数据。
解决方案
- 设置maxmemory-policy allkeys-lfu / allkeys-lru
- 业务层过滤低频访问数据,不放入缓存
快速记忆版(面试背诵)
- 穿透:不存在数据查 DB → 缓存空值、布隆过滤器
- 击穿:热点 key 过期 → 互斥锁、永不过期
- 雪崩:大量 key 同时过期 / 宕机 → 随机过期、集群、降级限流
- 不一致:双写顺序问题 → 先更 DB 再删缓存、异步更新
- 大 key→ 拆分、压缩、清理
- 并发竞争→ 分布式锁、Lua 脚本
