首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Redis 缓存击穿与雪崩的落地防护:互斥重建、过期抖动与空值缓存

Redis 缓存击穿与雪崩的落地防护:互斥重建、过期抖动与空值缓存

原创
作者头像
一只特立独行的兔先生
发布于 2026-10-31 09:28:25
发布于 2026-10-31 09:28:25
1470
举报

背景

缓存出问题时,数据库往往是第一个扛不住的。常见的三类问题容易被混在一起:

  • 穿透:查询的数据本来就不存在,每次都落到数据库。
  • 击穿:某个热点 key 过期的瞬间,大量并发请求同时回源。
  • 雪崩:大批 key 在同一时间过期,或缓存整体不可用,流量一起压向数据库。

本文给出每一类对应的工程做法和示例代码。

一、穿透:缓存空值与参数校验

请求的 id 在库里不存在,缓存里自然也没有,攻击或脏数据会让数据库持续承受无效查询。

  1. 入口先做参数合法性校验,比如 id 的范围、格式。
  2. 对查不到的结果缓存一个空值,并设置较短的过期时间:
代码语言:python
复制
NULL_MARK = "__NULL__"

def get_user(uid):
    v = redis.get(f"user:{uid}")
    if v is not None:
        return None if v == NULL_MARK else json.loads(v)
    row = db.query_user(uid)
    if row is None:
        redis.set(f"user:{uid}", NULL_MARK, ex=60)   # 空值短 TTL
        return None
    redis.set(f"user:{uid}", json.dumps(row), ex=3600)
    return row
  1. 数据量大、key 空间可预知时,可以用布隆过滤器提前拦截一定不存在的 key。布隆过滤器有误判率,只会把“不存在”误判成“可能存在”,不会漏掉真实存在的 key。

二、击穿:互斥重建

热点 key 过期时,只允许一个请求去重建缓存,其余请求等待或返回旧值。用 SET NX EX 实现简单的互斥锁:

代码语言:python
复制
def get_hot(key, loader, ttl=600):
    v = redis.get(key)
    if v is not None:
        return json.loads(v)
    lock = f"lock:{key}"
    token = uuid.uuid4().hex
    if redis.set(lock, token, nx=True, ex=10):
        try:
            data = loader()
            redis.set(key, json.dumps(data), ex=ttl)
            return data
        finally:
            # 只释放自己持有的锁
            if redis.get(lock) == token.encode():
                redis.delete(lock)
    time.sleep(0.05)
    return get_hot(key, loader, ttl)   # 实际使用要限制重试次数

注意事项:

  • 锁要设置过期时间,防止持锁进程崩溃造成死锁。
  • 释放锁前要校验持有者。上面“先 get 再 delete”不是原子的,严格场景应使用 Lua 脚本比较并删除。
  • 等待方要有重试上限和降级返回,避免请求堆积。

另一种做法是逻辑过期:缓存里存数据和一个逻辑过期时间,过期后仍返回旧值,同时由单个后台任务异步刷新。适合对短暂不一致可以容忍的热点数据。

三、雪崩:过期时间加随机抖动

批量预热的 key 如果使用相同的 TTL,会在同一刻集中过期。给 TTL 加上随机偏移:

代码语言:python
复制
import random
ttl = 3600 + random.randint(0, 600)
redis.set(key, value, ex=ttl)

此外:

  1. 限流和降级:回源数据库前加限流,超过阈值直接返回兜底数据或错误,保护数据库。
  2. 多级缓存:进程内缓存加 Redis,短时间的 Redis 抖动不会立刻打到数据库。
  3. 高可用:使用主从加故障切换或集群,避免单点导致缓存整体不可用。云上可使用云数据库 Redis 的多副本架构,具体规格以控制台为准。
  4. 预热和错峰:上线或重启后,提前加载热点数据,分批进行。

四、怎么验证防护有效

  1. 压测时手动删除热点 key,观察数据库查询数是否只有一次,而不是等于并发数。
  2. 监控缓存命中率、数据库 QPS 和慢查询,命中率骤降要有告警。
  3. 构造不存在的 id 批量请求,确认数据库没有被持续访问。
  4. 模拟 Redis 不可用,确认降级路径能工作。

小结

问题

核心手段

穿透

参数校验、空值缓存、布隆过滤器

击穿

互斥重建、逻辑过期

雪崩

TTL 随机抖动、限流降级、多级缓存、高可用

防护要分层做,单靠任何一种都不够,并且需要用压测和监控验证。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 背景
  • 一、穿透:缓存空值与参数校验
  • 二、击穿:互斥重建
  • 三、雪崩:过期时间加随机抖动
  • 四、怎么验证防护有效
  • 小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档