Redis 缓存穿透、击穿与雪崩:原理与实战解法
在高并发系统中,缓存几乎成了标配。它用极低的成本挡住了绝大部分读请求,让数据库能够专注于真正需要的写入与热点查询。但缓存并不是银弹,一旦设计不当,反而会把压力成倍地放大到数据库上。其中最常见的三个问题就是缓存穿透、缓存击穿与缓存雪崩。它们的名字很像,成因和解法却完全不同,本文把它们放在一起讲清楚。
一、缓存穿透:查一个不存在的数据
缓存穿透是指查询一个在缓存和数据库中都不存在的数据。由于数据根本不存在,缓存永远不会命中,于是每个请求都会穿过缓存直接打到数据库。恶意攻击者如果故意构造大量不存在的 ID 发起请求,数据库就会被无效查询拖垮。
解法主要有两种。第一种是缓存空值:当数据库也查不到时,把一个空结果(比如空字符串或特定标记)写入缓存,并设置一个较短的过期时间,这样同一个不存在的 key 下次就会命中缓存。第二种是布隆过滤器:在缓存之前加一层布隆过滤器,把所有存在的 key 预先写进去,请求先过布隆过滤器,不存在的直接拒绝。布隆过滤器有极小的误判率,但不会漏判,适合数据量大、攻击明显的场景。
二、缓存击穿:热点 key 突然失效
缓存击穿是指某个热点 key 在过期的瞬间,大量并发请求同时涌入,发现缓存为空后一起回源数据库,造成瞬时压力尖峰。它针对的是单个热点 key,和雪崩的“大量 key 同时失效”不同。
经典解法是互斥锁:缓存失效时,只允许一个线程去查询数据库并回填缓存,其他线程等待或返回旧值。在 Redis 中可以用 SETNX 实现分布式锁,拿到锁的线程负责回源,避免数据库被并发打满。另一种思路是逻辑过期:不给 key 设置物理过期时间,而是把过期时间存在 value 里,由后台异步刷新,这样就不存在“过期瞬间”的击穿问题。对于可预知的热点数据,提前预热也是简单有效的办法。
三、缓存雪崩:大量 key 同时失效
缓存雪崩是指在同一时刻大量 key 集中过期,或者 Redis 服务整体不可用,导致请求全部落到数据库,严重时数据库也会被拖垮,形成连锁故障。
应对雪崩的核心是“打散”和“冗余”。给过期时间加一个随机值,让 key 的失效时间分散开,避免集中过期;搭建 Redis 高可用集群(主从加哨兵或 Cluster),避免单点故障导致整个缓存层不可用;再配合多级缓存(本地缓存加分布式缓存)和限流降级手段,即使缓存层出问题,也能把损失控制在可接受范围内。
四、实战中的几点建议
首先,给缓存加上监控,重点关注命中率、慢查询和内存使用,命中率突然下降往往是问题的先兆。其次,对热点 key 做容量规划,避免单 key 过大或过热。最后,任何缓存策略都要经过压测验证,尤其是在大促或活动前,提前发现薄弱点。
缓存穿透、击穿、雪崩虽然表现不同,但本质都是“缓存失效后压力回源”。理解它们的成因,再结合业务特点选择合适的组合方案,才能让缓存真正成为系统的加速器,而不是隐患。
- 点赞
- 收藏
- 关注作者
评论(0)