Redis 三大缓存坑一次说透:穿透、击穿、雪崩的成因与解法 [复制链接]

管理员组

用 Redis 缓存后,高并发下常遇到穿透、击穿、雪崩三个问题。网上资料多但零散,这里把每个问题的成因、危害、代码级解法一次性讲清楚。

1. 缓存穿透:查了永远不存在的 key

恶意请求反复查一个数据库里不存在的 id,每次都能穿透缓存直达 DB,白名单被拖垮。解法是缓存空值 + 布隆过滤。

// 解法A:缓存空对象(简单可靠)
// 查库为 null 时也写入缓存,TTL 设短一些(如60秒)
if ($data === null) {
    $redis->setex($key, 60, serialize(null));
    return null;
}

// 解法B:布隆过滤器(能过滤99%不存在请求,需引入bloomfilter扩展或封装)
if (!$bloom->maybeHas($id)) {
    return null; // 一定不存在
}

2. 缓存击穿:热点 key 过期瞬间

一个超高并发的热点 key 恰好过期,瞬间请求全打到 DB。解法是互斥锁重建缓存或逻辑过期。

function getWithMutex(string $key, callable $loader, int $ttl) {
    $redis = Redis::client();
    $data = $redis->get($key);
    if ($data !== false) return unserialize($data);

    // 加锁:同一时刻只允许一个请求重建缓存
    $lockKey = $key . ':lock';
    if ($redis->set($lockKey, 1, ['NX', 'EX' => 5])) {
        $value = $loader();   // 只有持锁者查库
        $redis->setex($key, $ttl, serialize($value));
        $redis->del($lockKey);
        return $value;
    }
    // 未抢到锁:短暂等待后重试读缓存
    usleep(50 * 1000);
    return getWithMutex($key, $loader, $ttl);
}

3. 缓存雪崩:大量 key 同时过期

大量缓存同一时间失效,请求全部落到 DB。解法是过期时间加随机抖动 + 多级缓存。

// 过期时间加随机值(3~8分钟随机),避免同批 key 一起过期
$expire = $baseTtl + random_int(0, 300);
$redis->setex($key, $expire, serialize($data));

// 更稳的兜底:DB 层面做熔断,比如 ORM 查询加开关,异常时返回降级数据

小结

穿透治在"查空值也要缓存",击穿治在"热点 expired 要加锁重建",雪崩治在"过期时间错峰"。三个问题本质都是"缓存失效时如何保护 DB",理解了成因,代码就简单了。

最新回复

请先登录后再回复 登录

uid:1 管理员组
关注
错过了不该错过的人,那就是遗憾!
发帖 1418
评论 93
粉丝 1
关注 0
发新帖
目录
Redis 三大缓存坑一次说透:穿透、击穿、雪崩的成因与解法