★ 缓存穿透、缓存击穿、缓存雪崩是什么?如何应对?

结论先行:三者都是缓存失效场景下的高并发故障——穿透是"查了根本不存在的数据",击穿是"热点 key 恰好过期一瞬间被打爆",雪崩是"大量 key 同时过期或缓存整体宕机导致流量打到数据库"。应对思路分别是空值兜底与布隆过滤器、互斥锁与逻辑过期、过期时间加随机与高可用架构。

一、三兄弟对比表

问题触发场景核心危害主流方案
穿透请求查询不存在的数据缓存永远不命中,DB 被打垮参数校验、缓存空值、布隆过滤器
击穿单个热点 key 过期瞬间大量请求同时回源互斥锁重建、逻辑过期、热点永不过期
雪崩大量 key 同时过期或实例宕机流量瞬间压垮 DB过期时间加随机、多级缓存、限流降级、集群高可用

二、典型解决方案

  • 穿透:对不存在的 key 也写一个短 TTL 空值缓存;更彻底的是在缓存前加布隆过滤器,先过滤掉明显不存在的 key,注意布隆过滤器存在误判且不支持删除;
  • 击穿:重建缓存时加互斥锁,只让一个线程回源写缓存,其余线程短暂等待或直接读旧值;也可用逻辑过期,把过期时间放进 value,由后台线程异步刷新,读侧短暂容忍旧数据;
  • 雪崩:TTL 在基础值上加随机偏移量打散过期时刻;引入本地缓存做二级兜底;配合限流、熔断、降级保护数据库;缓存实例本身做哨兵/集群部署防止整体宕机;
  • 防护次序:入口参数校验与限流在前,布隆过滤与空值缓存居中,数据库连接池与慢查询治理兜底;
  • 识别配合:上线前通过监控与压测圈定热点并做缓存预热,用副本打散缓解击穿与雪崩的叠加效应。

三、互斥锁重建缓存的命令示例

# 只有抢锁成功者回源数据库并写缓存,其余请求短暂等待后重试
SET lock:hotkey 1 EX 3 NX        # 抢锁,3 秒自动过期防止死锁
# 业务代码中回源 DB 后写缓存,最后释放锁
# 抢锁失败者短暂休眠后重试读缓存,避免直接打 DB
DEL lock:hotkey                  # 释放锁(生产用 Lua 校验持有者后删除)

四、防护层次小结

  • 第一层:网关与业务入口的参数校验、黑名单与限流降级;
  • 第二层:缓存侧的布隆过滤器、空值缓存、随机 TTL 与热点打散;
  • 第三层:数据库侧的连接池保护与慢查询治理,作为最后兜底。
  • 落地顺序:先防穿透与雪崩这类"量"的问题,再处理击穿这类"点"的问题。

常见追问 / 记忆点

  • 追问:布隆过滤器能删除吗?答:标准布隆不支持删除,可用计数布隆或布谷鸟过滤器支持删除场景。
  • 追问:击穿和穿透怎么区分?答:穿透是数据不存在,击穿是数据存在但缓存刚过期。
  • 追问:热点数据可以永不过期吗?答:可以配合逻辑过期由后台异步刷新,用短暂不一致换取可用性。
  • 记忆点:穿透查"无",击穿打"单个热点",雪崩倒"一片",应对口诀:空值布隆防穿透、加锁异步防击穿、随机 TTL 防雪崩。
笔记加载中…