缓存三类问题是什么
缓存的三类问题根因不同:穿透是不存在的 key 反复回源;击穿是单个热点 key 过期瞬间并发重建;雪崩是大批 key 同时失效或缓存层整体不可用。对应处置分别是空值缓存与布隆过滤器、互斥重建或逻辑过期、TTL 抖动与降级预案。判断问题类型时先看回源请求的特征:是「缓存与库都没有」还是「缓存没命中但库里有」,两者的处置手段完全不同。
基本信息
| 穿透 | 查询不存在的 key,缓存与库都没有 |
|---|---|
| 击穿 | 单个热点 key 过期瞬间并发回源重建 |
| 雪崩 | 大批 key 同时失效或缓存层整体故障 |
| 常用手段 | 空值缓存、布隆过滤器、互斥重建、逻辑过期、TTL 抖动、限流降级 |
| 所属系统 | 缓存架构通用问题 |
问题对照
| 问题 | 触发场景 | 常用处置 |
|---|---|---|
| 穿透 | 查不存在的 key,缓存与库都没有 | 缓存空值(短 TTL)、参数校验、布隆过滤器 |
| 击穿 | 单个热点 key 过期,并发同时回源 | 互斥重建、逻辑过期后台刷新、预热 |
| 雪崩 | 大批 key 同时失效或缓存整体不可用 | TTL 加随机抖动、多级缓存、限流降级 |
典型使用场景
- 接口加固:对明显非法的查询参数先做校验,减少无效回源
- 热点预热:活动开始前把热点数据提前写入缓存
- 空值兜底:对确认不存在的 key 缓存一个短 TTL 的空标记
- 降级预案:缓存不可用时返回旧数据或限流,避免压力全落到数据库
- 监控告警:把缓存命中率与回源 QPS 纳入监控
互斥重建(伪代码)
互斥重建(伪代码)
def get_article(aid):
v = cache.get(aid) # 先读缓存
if v:
return v
if cache.setnx("lock:" + aid, "1", 10): # 抢到锁的请求去回源
try:
v = db.load(aid)
cache.set(aid, v, ttl=600) # 回填并设置过期时间
finally:
cache.delete("lock:" + aid) # 释放锁
else:
sleep(0.05) # 未抢到锁的短暂等待,生产要限次退避
return cache.get(aid)逻辑过期:value 里带 expire_at 字段而物理上不设过期,逻辑过期后先返回旧值同时异步刷新,适合能容忍短暂旧数据的热点页。
布隆过滤器存在误判,可能把不存在的 key 判为存在,只能作为一层过滤,不能当唯一防线。
空值缓存要能区分真实的空结果与异常导致的空结果,并设置较短 TTL 控制内存占用。