Redis
缓存穿透、击穿与雪崩:三个相似名词的因果区别
缓存穿透、击穿和雪崩都会把压力传递到数据库,但三者的原因不同。区分它们最简单的方法,是观察请求的 key 是否存在、影响的是单个热点还是大量 key。
缓存穿透:查询不存在的数据
攻击者或异常调用持续请求不存在的 key,缓存中没有,数据库里也没有,所以每次请求都会穿过缓存。
常见手段:
- 参数校验和接口限流;
- 对空结果设置较短 TTL;
- 使用布隆过滤器快速排除一定不存在的数据。
布隆过滤器可能误判“存在”,但不会把真实存在的数据判断为不存在。它节省了大量无效查询,却需要解决数据新增时同步更新的问题。
缓存击穿:单个热点突然失效
一个访问量很高的 key 到期,大量并发请求同时回源数据库,形成瞬时冲击。
可以使用互斥锁或 single-flight,只让一个请求负责加载数据,其余请求等待结果;也可以采用逻辑过期,让旧值短暂可用,由后台线程刷新。
这里存在可用性与一致性的权衡:等待加载保证结果较新,但增加延迟;返回旧值响应更稳,却允许短暂过期数据。
缓存雪崩:大量 key 同时失效
大量缓存使用相同 TTL,或 Redis 整体故障,会让大范围请求同时回到数据库。这不是一把热点锁就能解决的问题。
常见治理包括:
- TTL 加入随机抖动,避免同时过期;
- 热点数据预热和分批刷新;
- Redis 高可用与容量监控;
- 服务侧限流、熔断、降级;
- 数据库连接池和查询资源设置明确上限。
缓存不是越多越好
引入缓存后,系统从单一数据源变成多份副本,需要处理更新顺序、失效、重试和监控。设计方案时我会先明确可接受的不一致时间,再选择 Cache Aside 等策略,并为 Redis 不可用准备降级路径。