3. 缓存穿透与布隆过滤器
3.1 缓存穿透:问题定义
缓存穿透是指查询一个根本不存在的数据。由于缓存层不命中,请求直接穿透到后端数据库,而数据库也查询不到该记录,导致每次请求都直接访问数据库。
当大量请求并发查询同一个不存在的数据时,数据库会承受巨大的压力,甚至可能引发宕机。这是缓存系统中最常见且危害最大的问题之一。
核心危害: 恶意攻击或程序缺陷导致大量无效查询直接穿透缓存,击穿数据库保护层。
| 对比维度 | 缓存穿透 | 缓存击穿 | 缓存雪崩 |
|---|---|---|---|
| 查询对象 | 不存在的数据 | 热点数据过期 | 大量数据同时过期 |
| 影响范围 | 所有不存在 key | 单个热点 key | 多个 key 同时失效 |
| 典型场景 | 恶意攻击、爬虫 | 秒杀、爆款商品 | 缓存服务重启、批量过期 |
| 解决方案 | 布隆过滤器、空值缓存 | 互斥锁、逻辑过期 | 过期时间随机化、多级缓存 |
3.2 布隆过滤器原理
布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于判断一个元素一定不存在或可能存在于一个集合中。它由一个位数组和多个哈希函数组成。
核心工作机制
- 初始化: 创建一个长度为 m 的位数组,所有位初始化为 0。
- 添加元素: 使用 k 个哈希函数对元素计算,得到 k 个哈希值,将位数组中对应位置置为 1。
- 查询元素: 同样使用 k 个哈希函数计算,检查所有对应位是否都为 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.gitcd RedisBloommakeredis-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 缓存穿透防护架构
将布隆过滤器集成到缓存查询流程中,可以有效拦截对不存在数据的查询:
3.3.4 最佳实践与注意事项
- 容量规划: 根据业务数据量合理设置
BF.RESERVE的容量和错误率,避免频繁扩容。 - 初始化预热: 系统启动时,将数据库中所有存在的 key 预先添加到布隆过滤器中。
- 数据同步: 新增数据时,同时写入数据库和布隆过滤器;删除数据时,布隆过滤器无法删除,可考虑重建或使用布谷鸟过滤器。
- 错误率权衡: 错误率越低,内存占用越高。一般业务场景 1% 的错误率即可接受。
- 监控告警: 监控布隆过滤器的误判率,当误判率超过阈值时及时重建。
总结: 布隆过滤器是解决缓存穿透的最优方案,通过极小的内存开销(每个元素约 1-2 字节)即可拦截 99% 以上的无效查询,保护后端数据库。