首页/数据/数据库速查/缓存击穿(热点键瞬间失效)
Redis 运维与场景124 条

缓存击穿(热点键瞬间失效)

某个热点键过期瞬间,大量并发同时查库重建:用互斥锁让一个请求重建、其余等待,或逻辑过期让旧值先顶上。

数据库速查数据更新于 2026-10-13

缓存击穿是什么

缓存击穿指某个热点键在过期瞬间,大量并发请求同时发现缓存为空,于是一起回源查库并重建缓存,数据库被同一个查询瞬间打满。它与雪崩(大面积同时失效)和穿透(查询本就不存在的数据)的区别在于对象:击穿针对的是单个高并发访问的热点键。常用对策是互斥重建与逻辑过期。

基本信息

触发条件热点键过期、首次加载或缓存被主动删除
主要对策互斥重建、逻辑过期、热点白名单、提前预热
互斥实现SET key NX PX 抢锁,拿到锁的请求负责回源
逻辑过期值内嵌过期时间,过期后由一个请求异步刷新
关键风险锁持有者异常未完成时,其他请求要有兜底路径

典型使用场景

  • 首页热点商品:被高频访问且过期时间集中
  • 秒杀商品详情:流量峰值集中在一个键上
  • 大促配置数据:定时批量刷新导致集中失效
  • 首屏接口:缓存预热不足时首个请求承担全部回源
  • 热点识别:按访问频率统计出需要特殊处理的热点键
  • 降级设计:确定缓存失效时返回旧值还是返回兜底内容

互斥重建示例

互斥重建示例
def get_hot(key):
    v = redis.get(key)
    if v is not None:
        return v
    # 抢锁重建:只放一个请求去查库
    if redis.set(key + ':lock', '1', nx=True, px=3000):
        try:
            row = db.query_hot(key)
            redis.set(key, row, ex=300)
            return row
        finally:
            redis.delete(key + ':lock')
    # 没抢到锁:短暂重试,超过上限就走兜底值
    for _ in range(3):
        time.sleep(0.05)
        v = redis.get(key)
        if v is not None:
            return v
    return fallback(key)   # 兜底:旧值或默认内容,避免请求堆积

对策对照

对策原理代价
互斥重建只放一个请求回源,其余等待等待期间延迟上升,锁需超时保护
逻辑过期旧值先顶上,异步刷新短时间读到旧数据
热点永不过期运营后台主动刷新需要热点维护机制,易漏刷
提前预热失效前主动加载需要预测访问模式
互斥重建要加自旋上限与超时:锁持有者超时未完成时,其他请求要有兜底路径,避免整体卡死。
抢锁失败的请求如果无上限自旋等待,一旦锁持有者异常,所有请求会堆在等待上,体验比直接回源更差;务必设置重试次数上限与降级返回。

易错点

  • 热点键设了统一过期时间,到点全部请求一起回源
  • 互斥锁没有过期时间,持锁进程崩溃后重建入口永久堵死
  • 抢锁失败的请求无限自旋,把应用线程池占满
  • 只给 Redis 加锁却不做双检,拿到锁后仍可能重复回源
  • 缓存重建期间没有降级策略,数据库压力直接传导到用户请求

数据来源与参考

  • Redis 官方文档: 使用模式
  • 缓存击穿治理实践

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌