Redis 缓存穿透解决

Redis 缓存穿透解决

缓存穿透是常见问题,恶意请求能把数据库打挂。

1. 什么是缓存穿透

现象: 请求的数据在缓存和数据库中都不存在,每次请求都直接打到数据库。

危害:

  • 恶意攻击时数据库压力大
  • 正常请求被拖慢
  • 数据库CPU飙升

2. 为什么会穿透

  • 查询一个不存在的ID
  • 缓存没有命中
  • 数据库也查不到
  • 请求直接穿透到数据库

3. 解决方案一:缓存空值

思路: 即使数据库查不到,也在Redis存一个空值,设置短过期时间。

function getUser($id) {
    $key = "user:$id";
    $user = $redis->get($key);

    if ($user !== false) {
        // 空值标记
        if ($user === 'null') {
            return null;
        }
        return json_decode($user, true);
    }

    // 查数据库
    $user = $db->query("SELECT * FROM users WHERE id = $id");

    if ($user) {
        // 存在就缓存1小时
        $redis->setex($key, 3600, json_encode($user));
    } else {
        // 不存在也缓存,5分钟过期
        $redis->setex($key, 300, 'null');
    }

    return $user;
}

优点: 简单有效
缺点: 占内存,可能被恶意key刷爆

4. 解决方案二:布隆过滤器

思路: 在缓存前面加一层布隆过滤器,不存在的key直接拦截。

原理:

  • 所有存在的数据先存到布隆过滤器
  • 请求先过布隆过滤器
  • 不存在直接返回,不查缓存和数据库

PHP 示例(用 Redis 的布隆过滤器模块):

# 加载 RedisBloom 模块
redis-cli BF.ADD user:1
redis-cli BF.EXISTS user:1
function getUser($id) {
    $key = "user:$id";

    // 先过布隆过滤器
    if (!$redis->rawCommand('BF.EXISTS', 'user_filter', $id)) {
        return null; // 一定不存在
    }

    // 布隆说可能存在,再查缓存
    $user = $redis->get($key);
    if ($user) {
        return json_decode($user, true);
    }

    // 查数据库...
}

优点: 内存占用小,效率高
缺点: 有误判率,实现复杂

5. 解决方案三:参数校验

思路: 从源头过滤非法请求。

function getUser($id) {
    // 参数校验
    if ($id <= 0 || !is_numeric($id)) {
        return null;
    }

    // 正常查询逻辑...
}

适用: ID类查询,不合法直接拦截

6. 三种方案对比

方案 优点 缺点 适用场景
缓存空值 简单 占内存 数据量不大
布隆过滤器 高效 误判,复杂 数据量大
参数校验 最直接 只防非法 ID类请求

7. 生产建议

1)组合使用

  • 先做参数校验
  • 再缓存空值
  • 大流量用布隆过滤器

2)空值过期时间要短

  • 5分钟到10分钟
  • 不要太长

3)监控异常请求

  • 发现大量404要警惕
  • 及时加防护

4)接口限流

  • 用 Nginx 或网关限流
  • 防止恶意刷

8. 缓存雪崩和击穿

缓存穿透: 查不存在的数据
缓存击穿: 热点key过期,大量请求打数据库
缓存雪崩: 大量key同时过期

区分清楚: 三个问题现象类似但原因不同,解决方案也不同。

总结

Redis 缓存穿透解决要点:

  • 查不存在的数据穿透到数据库
  • 缓存空值是最简单方案
  • 布隆过滤器适合大数据量
  • 参数校验从源头拦截
  • 空值过期时间要短
  • 生产建议组合使用
  • 注意和雪崩、击穿区分开
  • 监控异常请求
  • 接口加限流

缓存穿透是面试高频题,也是生产常见问题,一定要掌握。


emer 发布于  2026-10-9 07:36 

Redis 缓存穿透解决

Redis 缓存穿透解决

缓存穿透是常见问题,大量请求查询不存在的数据,直接打到数据库。这篇讲怎么解决。

1. 什么是缓存穿透

用户查询一个不存在的数据,Redis 里没有,每次都去查数据库。恶意攻击的话,数据库扛不住。

2. 解决方案一:缓存空值

查询数据库也没结果,就缓存一个空值,设置短过期时间。

function getUser($id) {
    $key = "user:$id";

    // 先查缓存
    $user = $redis->get($key);
    if ($user !== false) {
        return json_decode($user, true);
    }

    // 查数据库
    $user = $db->query("SELECT * FROM users WHERE id = $id");

    if ($user) {
        // 缓存有数据的结果
        $redis->setex($key, 3600, json_encode($user));
    } else {
        // 缓存空值,短时间过期
        $redis->setex($key, 60, '');
    }

    return $user;
}

优点: 简单粗暴
缺点: 浪费内存,可能导致不一致

3. 解决方案二:布隆过滤器

在缓存前面加一层布隆过滤器,不存在的 key 直接拦截。

// 使用 RedisBloom 模块
// 添加到布隆过滤器
$redis->rawCommand("BF.ADD", "user_filter", "1001");

// 查询是否存在
$exists = $redis->rawCommand("BF.EXISTS", "user_filter", "1001");
if (!$exists) {
    return null; // 直接返回,不查数据库
}

原理: 用二进制数组和多个哈希函数,判断一个 key 一定不存在或者可能存在。

优点: 内存占用小,效率高
缺点: 有一定误判率,不支持删除

4. 两种方案对比

方案 优点 缺点 适用场景
缓存空值 简单 浪费内存 数据量小
布隆过滤器 高效省内存 有误差 数据量大

5. 其他注意事项

  • 接口增加参数校验,不合法的 id 直接拒绝
  • 增加接口访问限流,防止恶意攻击
  • 黑名单机制,频繁查不存在的 IP 封掉

总结

缓存穿透解决思路:

  1. 缓存空值: 简单,适合小数据量
  2. 布隆过滤器: 高效,适合大数据量
  3. 加限流和校验: 从入口防护

生产环境推荐布隆过滤器 + 缓存空值组合使用。


emer 发布于  2026-10-8 07:06 

Redis 缓存穿透解决

Redis 缓存穿透解决方案

缓存穿透是指查询一个数据库里根本不存在的数据,因为缓存里也没有,所以每次请求都打到数据库。如果有人恶意攻击,数据库可能被打挂。

什么是缓存穿透

正常流程:先查缓存,缓存有就直接返回,没有再查数据库,然后写入缓存。

如果查询的数据数据库里也没有,那缓存永远都不会命中,每次请求都会查数据库,这就是缓存穿透。

解决方案一:缓存空值

最简单的办法,数据库查不到也往缓存里写一个空值,设个短过期时间。

$data = $redis->get($key);
if ($data === null) {
    $data = $db->query($sql);
    if ($data === null) {
        // 缓存空值,60秒过期
        $redis->setex($key, 60, '');
    } else {
        $redis->setex($key, 3600, $data);
    }
}

优点:简单直接
缺点:会占用更多缓存空间,大量空值缓存会浪费内存

解决方案二:布隆过滤器

在缓存前面加一层布隆过滤器,先判断数据是否存在,不存在直接返回。

布隆过滤器的原理是用一个大的位数组和多个哈希函数,把存在的数据标记为1。查询时如果所有哈希位置都是1,说明可能存在;只要有一个位置是0,说明一定不存在。

优点:内存占用小,效率高
缺点:有一定误判率(说存在可能不存在,说不存在一定不存在)

两种方案对比

方案 优点 缺点 适用场景
缓存空值 简单 浪费内存 数据量小,穿透不严重
布隆过滤器 内存效率高 有误差 数据量大,穿透严重

总结

缓存穿透是常见的缓存问题,小项目用缓存空值就够了,大项目数据量大就上布隆过滤器。两种方案都能解决问题,根据实际场景选就行。


emer 发布于  2026-10-4 10:43 
'); })();