Redis 缓存三大问题:穿透、击穿、雪崩与解法

一、缓存三大问题是什么

引入 Redis 后最常踩的三个坑:穿透、击穿、雪崩。名字像,但成因和解法不同。

问题 成因 特征
穿透 查不存在的数据,缓存和库都没有 请求直击数据库,恶意可用不存在 key 打垮 DB
击穿 某个热点 key 过期瞬间,大量请求同时回源 单点热点失效,并发压到 DB
雪崩 大量 key 同一时间集中过期 / 缓存宕机 DB 压力陡增甚至被打死

二、穿透:让”查不到”也有缓存

  • 缓存空值:查不到也写个短 TTL 的空对象,拦住重复查询;
  • 布隆过滤器:前置一层,根本不存在的 key 直接拒绝。
def get_user(uid):
    val = redis.get(f"user:{uid}")
    if val is not None:
        return None if val == b"NULL" else json.loads(val)
    row = db.query(uid)
    if row is None:
        redis.setex(f"user:{uid}", 60, "NULL")   # 缓存空值 60s
        return None
    redis.setex(f"user:{uid}", 3600, json.dumps(row))
    return row

三、击穿:热点 key 别让它”集体回源”

  • 互斥重建:发现缓存失效,只放一个线程去查库,其余等待;
  • 逻辑过期:key 不真过期,value 带过期时间字段,异步刷新。

四、雪崩:别让过期时间”约好一块走”

  • 过期时间加随机:TTL = 基础 + 随机抖动,错开失效;
  • 多级缓存:本地缓存(Caffeine) + Redis,Redis 挂了还有本地兜底;
  • 限流降级:缓存故障时对回源做限流,保护 DB。

五、小结

穿透靠”空值 + 布隆”,击穿靠”互斥 + 逻辑过期”,雪崩靠”随机 TTL + 多级 + 限流”。三者都做好了,缓存才真正扛压而不是制造事故。