Redis缓存穿透击穿雪崩区别与防护方案
时间:2026-10-19 07:23 作者:emer 分类: 无
前言
Redis 把热点数据放进内存提速,但缓存一旦失效或被恶意穿透,数据库会被瞬间打垮。很多人把穿透、击穿、雪崩混为一谈,三者成因不同,防护手段也不一样,本篇一次讲清区别和方案。
一、缓存穿透:查不存在的数据
攻击者或程序反复查询一个数据库里根本不存在的 key,缓存永远不命中,每次都打到 MySQL。
- 典型:刷不存在的用户ID、商品ID。
- 防护:
- 布隆过滤器(Bloom Filter):请求先过过滤器,不存在直接拦截,不查库;
- 缓存空值:对查不到的结果也缓存一个空对象并设短过期时间(如60秒)。
// 伪代码:缓存空值
$user = $db->find($id);
if ($user === null) {
$redis->setex("u:$id", 60, 'NULL');
return null;
}
$redis->setex("u:$id", 3600, json_encode($user));
二、缓存击穿:热点key过期瞬间
一个被高频访问的热点 key 突然过期,大量并发同时打到数据库重建缓存。和穿透区别:数据真实存在,只是刚好过期。
- 防护:
- 热点key逻辑过期,不设物理TTL,后台异步刷新;
- 加互斥锁(SETNX),只让一个线程回源重建,其余等待。
// SETNX 单线程重建
$lock = $redis->setnx("lock:u:$id", 1);
if ($lock) {
$redis->expire("lock:u:$id", 10);
$data = $db->find($id);
$redis->setex("u:$id", 3600, json_encode($data));
}
三、缓存雪崩:大量key同时过期
大批缓存同一时间失效,数据库承压暴增。和击穿区别:击穿是单个热点,雪崩是大面积。
- 防护:过期时间加随机偏移,避免同时失效;多级缓存;Redis集群高可用;限流降级兜底。
$ttl = 3600 + mt_rand(0, 600); // 3600~4200 秒随机
$redis->setex("list:$page", $ttl, json_encode($rows));
四、三者对比速记
- 穿透:数据不存在 → 布隆过滤器 + 缓存空值;
- 击穿:热点key过期 → 互斥锁 + 逻辑过期;
- 雪崩:大批key同时过期 → TTL随机 + 高可用 + 限流。
总结
先分清"查不存在""单点过期""批量过期"三种场景,再对应布隆过滤器、互斥锁、随机TTL,就能把数据库挡在缓存后面。
遇到问题加QQ23979811 协助处理