缓存雪崩与击穿是什么
缓存雪崩指大批缓存键在同一时间失效,或缓存层整体宕机,导致流量瞬间全部压向数据库;缓存击穿指单个热点键失效的刹那,大量并发请求同时回源重建同一份数据。两者的后果相同:源库被瞬时打满,进而拖垮整个链路。对策包括给过期时间加随机抖动、用互斥锁让同一时刻只有一个请求回源、逻辑过期配合后台异步刷新,以及让热点数据多副本或本地缓存承接读流量。
基本信息
| 雪崩 | 大批键同时失效或缓存层不可用,流量集中打到源库 |
|---|---|
| 击穿 | 单个热点键失效瞬间,大量请求并发回源重建 |
| 穿透 | 查询不存在的数据,每次都绕过缓存直查源库 |
| 首要对策 | TTL 加随机抖动;互斥锁单飞重建;逻辑过期后台刷新 |
| 应急兜底 | 回源超限时返回旧值或降级数据,保护存储层 |
典型使用场景
- 首页与活动页:热点数据集中,失效瞬间最易击穿,需要提前预热
- 缓存层维护窗口:重启或扩容时命中率骤降,要有限流与降级预案
- 整点批量刷新:定时预热任务与集中过期叠加时容易形成雪崩
- 刚上线的爆款商品:读流量骤增,本地缓存与热点复制可分摊压力
- 爬虫与异常查询:不存在的键被反复查询,需空值缓存或布隆过滤器拦截
- 促销前压测:注入批量失效场景,验证单飞重建与降级开关是否可用
三类问题与对策
| 问题 | 触发条件 | 对策 |
|---|---|---|
| 雪崩 | 大批键同时过期或缓存集群故障 | TTL 加随机抖动;多级缓存;缓存不可用时限流回源 |
| 击穿 | 热点键过期瞬间并发回源 | 互斥锁单飞重建;逻辑过期后台刷新;热点键不过期 |
| 穿透 | 查询不存在的数据 | 空值缓存设短过期;布隆过滤器前置拦截;参数校验 |
| 回源风暴 | 重建期间无并发控制 | 单飞 + 回源限流,超出部分直接返回旧值 |
单飞重建与逻辑过期
单飞重建与逻辑过期
# 方案一:互斥锁单飞,保证同一键同一时刻只有一个请求回源
if not cache.get(key):
if lock.acquire(key, timeout=1s): # 只放一个请求去重建
value = load_from_db(key)
cache.set(key, value, ttl=jitter(300s)) # TTL 加随机抖动
lock.release(key)
else:
sleep(50ms) # 其余请求短暂等待后重试
return cache.get(key) or stale_value(key)
# 方案二:逻辑过期,值内记录过期时间,后台异步刷新,读侧先返回旧值
# 兜底:回源量超过阈值时直接返回旧值并告警,避免数据库被打满重建必须控并发:无锁并发回源等于把数据库暴露在整个失效窗口上,键越热点破坏力越大。
缓存层自身也会故障:只设计「缓存命中」路径而没有「缓存不可用」时的限流与降级方案,等于把可用性押在缓存上。