Redis布隆过滤器容量增长为什么会增加内存
来源:17golang原创
时间:2026-10-13 18:52:56 107浏览 收藏
我第一次把 Redis 布隆过滤器接到一批持续增长的 ID 黑名单时,最先看到的不是命中率变化,而是 Redis 内存曲线在某些时间点向上跳。原因通常不是每个元素保存了一份字符串,而是过滤器超过初始 capacity 后,Redis 为它增加了新的子过滤器。每个子过滤器都需要自己的位数组和哈希函数信息,所以总占用会继续增长。
官方地址:https://redis.io/docs/latest/commands/bf.reserve/
Redis 布隆过滤器的容量不是一个“永远封顶”的总容量。默认配置允许扩展;超过初始容量后会创建子过滤器,BF.INFO中的FILTERS和SIZE可以帮助判断内存增长是否来自这条路径。
容量超过后,Redis 实际增加了什么
BF.RESERVE 创建过滤器时,Redis 会先按给定的误判率和初始容量准备一个子过滤器。新增元素数量达到这一段容量后,如果过滤器允许扩展,就再创建一个子过滤器。查询时需要按规则检查这些子过滤器,写入与查询的工作量也会随子过滤器数量增加。

因此,“容量增长导致内存变大”更准确的解释是:容量增长让过滤器需要更多位来表示更多元素;如果增长跨过了初始容量边界,Redis 还会保留并维护多个子过滤器,而不是把原来的位数组简单改成一个更大的数组。
BF.RESERVE 的三个参数怎样影响内存
最小创建命令如下。这里的 error_rate 是允许的误判为存在的概率,capacity 是预计要放入的条目数。
# 预留约 100 万个条目,允许 0.1% 的误判率 BF.RESERVE user:seen 0.001 1000000 # 明确设置扩展倍率;容量用尽后按上一个子过滤器的大小扩展 BF.RESERVE user:seen 0.001 1000000 EXPANSION 2
误判率越低,每个元素所需的位数通常越多,因此同样的容量下内存也会增加。官方文档给出的近似关系是:所需位数与 -ln(error_rate) / ln(2)^2 成正比;实际占用还会受到模块实现和内存分配的影响,不能把公式结果当成精确的 Redis 进程内存。
EXPANSION 决定后续子过滤器相对前一个子过滤器的容量倍率。倍率为 2 时,子过滤器更少,适合容量难以预测的场景;倍率为 1 时,扩容颗粒更小,可能减少一次性多分配的内存,但更容易积累多个子过滤器。默认扩展倍率是 2。
用 BF.INFO 把内存增长拆开看
不要只看 Redis 的总内存曲线。对布隆过滤器本身,先读取容量、占用大小、子过滤器数量和已插入条目数:
# 读取过滤器的容量、字节数、子过滤器数量和扩展倍率 BF.INFO user:seen # 单独读取四个关键观察项,便于写入监控采集 BF.INFO user:seen SIZE BF.INFO user:seen FILTERS BF.INFO user:seen CAPACITY BF.INFO user:seen ITEMS
如果 FILTERS 从 1 变成 2 或更多,同时 SIZE 上升,基本可以把这段增长归因到扩展子过滤器。CAPACITY 表示在继续扩展前当前子过滤器还能接收的独立条目数量,ITEMS 则是被识别为新条目的数量;重复添加同一个元素不能简单等同于新增容量消耗。
这些信息适合组成一个轻量的自动化巡检回路:写入端按固定间隔采集 FILTERS、SIZE 和 ITEMS,门禁规则在子过滤器数量异常增长时发出通知,复盘时再对照实际业务容量是否已经超出创建时的估计。
容量怎么规划,才能少付扩容代价

我会先按业务保留期内的去重条目数估算容量,再决定是否允许扩展。下面这张表更适合作为上线前的参数速查:
| 场景 | 参数思路 | 代价 |
|---|---|---|
| 容量可准确预估 | 把 capacity 设在预计值附近 | 初始内存更可控,减少多子过滤器查询 |
| 容量未知且会持续增长 | 允许扩展,必要时使用 EXPANSION 2 或更高 | 减少子过滤器数量,但单次扩展可能申请更多内存 |
| 希望扩展颗粒更细 | 使用 EXPANSION 1 | 新增子过滤器更小,但长期可能有更多过滤器 |
| 超容量必须显式失败 | 使用 NONSCALING | 内存更容易封顶,但达到容量后写入会报错 |
NONSCALING 会禁止创建额外子过滤器。它的内存通常略低于可扩展过滤器,但代价是超过初始容量后不能继续静默接收数据。对于黑名单、去重标记这类可以提前切换新 key 的业务,显式失败有时比无边界扩展更容易运营。
扩容后的失败处理和通知回路
如果选择了自动扩展,应用层仍要把容量告警当成正常的运营信号,而不是等 Redis 到达 maxmemory 才处理。可以把处理分成四步:
- 定期读取
BF.INFO key SIZE、FILTERS和ITEMS,保存时间序列。 - 当
FILTERS增长或ITEMS接近业务预计上限时,通知负责缓存容量的人。 - 重新估算保留期、误判率和容量,决定新建更合适容量的过滤器,还是接受继续扩展。
- 切换 key 时保留读旧过滤器的过渡期,避免刚迁移就把仍在使用的数据判成“不存在”。
不要把 SIZE 当成业务数据量的精确线性函数。误判率、扩展倍率、子过滤器数量和模块版本都会改变实际表现;更可靠的做法是用 BF.INFO 记录趋势,再结合应用保留策略做决策。
几个容易混淆的问题
capacity 是总容量还是第一段容量?
在允许扩展的情况下,它首先描述初始子过滤器的容量。过滤器可以通过新子过滤器继续接收条目,但子过滤器越多,内存和查询开销越高。
为什么不直接把 capacity 设得很大?
设大可以减少扩展次数,但会把内存预算提前交给过滤器;如果预计条目量不稳定,还需要在空置内存和后续扩展之间取舍。
EXPANSION 越大越省内存吗?
不能这样理解。较大的倍率通常减少子过滤器数量,但新子过滤器也更大;它优化的是扩展次数与长期结构,不保证任意时刻的总内存都最低。
总结
Redis 布隆过滤器容量增长后内存增加,有两层原因:更多条目需要更多位;超过初始 capacity 后,默认扩展会创建新的子过滤器,而每个子过滤器都需要额外的位数组和哈希信息。先用 BF.INFO 看 FILTERS 与 SIZE,再依据容量可预测程度选择预估容量、EXPANSION 或 NONSCALING,比只盯着 Redis 总内存更容易做出正确判断。
-
472 收藏
-
117 收藏
-
426 收藏
-
171 收藏
-
113 收藏
-
146 收藏
-
370 收藏
-
323 收藏
-
332 收藏
-
197 收藏
-
337 收藏
-
340 收藏
-
166 收藏
-
195 收藏
-
229 收藏
-
136 收藏
-
421 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习