3. 缓存穿透与布隆过滤器

3.1 缓存穿透:问题定义

缓存穿透是指查询一个根本不存在的数据。由于缓存层不命中,请求直接穿透到后端数据库,而数据库也查询不到该记录,导致每次请求都直接访问数据库。

当大量请求并发查询同一个不存在的数据时,数据库会承受巨大的压力,甚至可能引发宕机。这是缓存系统中最常见且危害最大的问题之一。

核心危害: 恶意攻击或程序缺陷导致大量无效查询直接穿透缓存,击穿数据库保护层。
对比维度 缓存穿透 缓存击穿 缓存雪崩
查询对象 不存在的数据 热点数据过期 大量数据同时过期
影响范围 所有不存在 key 单个热点 key 多个 key 同时失效
典型场景 恶意攻击、爬虫 秒杀、爆款商品 缓存服务重启、批量过期
解决方案 布隆过滤器、空值缓存 互斥锁、逻辑过期 过期时间随机化、多级缓存

3.2 布隆过滤器原理

布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于判断一个元素一定不存在或可能存在于一个集合中。它由一个位数组和多个哈希函数组成。

核心工作机制

  1. 初始化: 创建一个长度为 m 的位数组,所有位初始化为 0。
  2. 添加元素: 使用 k 个哈希函数对元素计算,得到 k 个哈希值,将位数组中对应位置置为 1。
  3. 查询元素: 同样使用 k 个哈希函数计算,检查所有对应位是否都为 1:
    • 如果任意一位为 0,则元素一定不存在。
    • 如果所有位都为 1,则元素可能存在(存在误判率)。
重要特性: 布隆过滤器不能删除元素(标准版),且存在假阳性(误判存在),但没有假阴性(不会漏判已存在的元素)。
布隆过滤器工作原理 输入元素 Hash 1 Hash 2 Hash k 位数组(长度 m) 1 0 1 0 1 0 1 0 0 1 查询元素 任意位为 0 所有位为 1 一定不存在 可能存在

3.3 Redis 布隆过滤器模块(RedisBloom)

Redis 官方提供了 RedisBloom 模块,为 Redis 增加了布隆过滤器、布谷鸟过滤器等概率型数据结构支持。通过该模块,开发者可以直接在 Redis 中使用布隆过滤器,无需自行实现位数组和哈希函数。

3.3.1 安装 RedisBloom

RedisBloom 支持多种安装方式,推荐使用 Docker 或编译安装:

安装方式 命令 / 步骤 说明
Docker docker run -p 6379:6379 redislabs/rebloom 一键启动,包含 Redis + RedisBloom
编译安装 git clone https://github.com/RedisBloom/RedisBloom.git
cd RedisBloom
make
redis-server --loadmodule ./redisbloom.so
需要 Go 编译环境
Redis Stack docker run -p 6379:6379 redis/redis-stack-server 包含 RedisBloom 在内的多个模块

3.3.2 核心命令与使用

RedisBloom 提供了简洁的命令接口,主要包含以下操作:

# 1. 创建布隆过滤器(指定错误率和容量)
BF.RESERVE myfilter 0.01 10000

# 2. 添加元素
BF.ADD myfilter "user:1001"
BF.ADD myfilter "user:1002"

# 3. 批量添加
BF.MADD myfilter "user:1003" "user:1004" "user:1005"

# 4. 检查元素是否存在
BF.EXISTS myfilter "user:1001"    # 返回 1(可能存在)
BF.EXISTS myfilter "user:9999"    # 返回 0(一定不存在)

# 5. 批量检查
BF.MEXISTS myfilter "user:1001" "user:9999"
参数说明: BF.RESERVE 的第二个参数是错误率(0.01 表示 1%),第三个参数是预期容量(10000 个元素)。错误率越低,位数组越大,内存占用越高。

3.3.3 缓存穿透防护架构

将布隆过滤器集成到缓存查询流程中,可以有效拦截对不存在数据的查询:

布隆过滤器防护缓存穿透架构 客户端请求 布隆过滤器 BF.EXISTS Redis 缓存 GET / SET 数据库 MySQL ① 查询 ② 不存在 → 直接返回空 ② 可能存在 ③ 命中 → 直接返回 ③ 未命中 ④ 查询数据库 ⑤ 回写缓存 ⑥ 返回结果给客户端

3.3.4 最佳实践与注意事项

  • 容量规划: 根据业务数据量合理设置 BF.RESERVE 的容量和错误率,避免频繁扩容。
  • 初始化预热: 系统启动时,将数据库中所有存在的 key 预先添加到布隆过滤器中。
  • 数据同步: 新增数据时,同时写入数据库和布隆过滤器;删除数据时,布隆过滤器无法删除,可考虑重建或使用布谷鸟过滤器。
  • 错误率权衡: 错误率越低,内存占用越高。一般业务场景 1% 的错误率即可接受。
  • 监控告警: 监控布隆过滤器的误判率,当误判率超过阈值时及时重建。
总结: 布隆过滤器是解决缓存穿透的最优方案,通过极小的内存开销(每个元素约 1-2 字节)即可拦截 99% 以上的无效查询,保护后端数据库。