面对海量 URL 或邮件地址去重,传统 Set 集合会消耗大量内存。Redis 4.0 引入布隆过滤器插件,通过位数组与多个哈希函数实现高空间利用率的概率性去重。本文将梳理其工作原理、安装方式、核心命令及误判率调优策略,帮助你在实际业务中快速落地并合理配置参数。
典型应用场景与空间优势
布隆过滤器(Bloom Filter)是 Redis 4.0 版本提供的新功能,作为插件加载到 Redis 服务器中,提供强大的去重能力。相比于 Set 集合,布隆过滤器在空间上能节省 90% 以上,但去重率大约在 99% 左右,存在约 1% 的误判率。这种误差由其自身结构决定,属于空间与精度之间的权衡。在处理海量数据时,1% 的误判率通常可以忽略。
典型场景包括:
- 爬虫系统 URL 去重:百度爬虫每天面临海量 URL,需对已抓取地址去重以提升效率。若使用 Set 装载所有 URL,会造成严重的空间浪费。
- 垃圾邮件过滤:过滤过程中允许少量误判,但相比牺牲宝贵的性能和空间,该误差微不足道。
位数组与哈希映射的工作原理
布隆过滤器是一个高空间利用率的概率性数据结构,由二进制向量(位数组)和一系列随机映射函数(哈希函数)组成。它使用 exists() 判断元素是否存在:当判定存在时,元素只是可能存在;当判定不存在时,元素肯定不存在。误判概率大约在 1% 左右。
添加元素流程
位数组初始状态全为 0。添加 key 时,使用多个不同的 hash 函数对元素值进行计算,得到多个哈希值。将每个哈希值与位数组长度取余,得到对应的位数组位置,并将这些位置的值置为 1。每个 hash 函数对应一个不同位置,完成添加(add)操作。

图1:布隆过滤器原理
判定元素是否存在
判断元素时,再次执行相同的哈希计算,得到对应的位数组位置。若其中任意一个位置为 0,则元素肯定不存在;若所有位置均为 1,则元素可能存在。
为什么是“可能存在”
被置为 1 的位置可能由其他元素的操作导致。例如元素 1 和元素 2 同时将某个位置变为 1,此时无法判定元素 1 一定存在。这是布隆过滤器产生误判的根本原因。
Docker 与编译安装步骤
Redis 4.0 之后,布隆过滤器作为插件正式使用,需单独安装 RedisBloom。
Docker 安装
docker pull redislabs/rebloom:latest docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest docker exec -it redis-redisbloom bash redis-cli #测试是否安装成功 127.0.0.1:6379> bf.add www.biancheng.net hello
直接编译安装
下载地址: https://github.com/RedisBloom/RedisBloom 解压文件: unzip RedisBloom-master.zip 进入目录: cd RedisBloom-master 执行编译命令,生成redisbloom.so 文件: make 拷贝至指定目录: cp redisbloom.so /usr/local/redis/bin/redisbloom.so 在redis配置文件里加入以下配置: loadmodule /usr/local/redis/bin/redisbloom.so 配置完成后重启redis服务: sudo /etc/init.d/redis-server restart #测试是否安装成功 127.0.0.1:6379> bf.add www.biancheng.net hello
常用命令与参数调优
| 命令 | 说明 |
|---|---|
| bf.add | 只能添加元素到布隆过滤器。 |
| bf.exists | 判断某个元素是否在于布隆过滤器中。 |
| bf.madd | 同时添加多个元素到布隆过滤器。 |
| bf.mexists | 同时判断多个元素是否存在于布隆过滤器中。 |
| bf.reserve | 以自定义的方式设置布隆过滤器参数值,共有 3 个参数分别是 key、error_rate(错误率)、initial_size(初始大小)。 |
命令应用示例
127.0.0.1:6379> bf.add spider:url www.biancheng.net (integer) 1 127.0.0.1:6379> bf.exists spider:url www.biancheng.net (integer) 1 127.0.0.1:6379> bf.madd spider:url www.taobao.com www.123qq.com 1) (integer) 1 2) (integer) 1 127.0.0.1:6379> bf.mexists spider:url www.jd.com www.taobao.com 1) (integer) 0 2) (integer) 1
Python 误判率测试与最佳实践
使用 Python 测试布隆过滤器的误判率,代码如下:
import redis
size=10000
r = redis.Redis()
count = 0
for i in range(size):
#添加元素,key为userid,值为user0...user9999
r.execute_command("bf.add", "userid", "user%d" % i)
#判断元素是否存在,此处切记 i+1
res = r.execute_command("bf.exists", "userid", "user%d" % (i + 1))
if res == 1:
print(i)
count += 1
#求误判率,round()中的5表示保留的小数点位数
print("size: {} ,error rate:{}%".format(size, round(count / size * 100, 5)))执行三次测试,size 从小到大,输出结果如下:
size: 1000 , error rate: 1.0% size: 10000 , error rate: 1.25% size: 100000 , error rate: 1.305%
结果显示误判率在 1% 左右,且随着 size 增大,错误率会升高。可通过 bf.reserve 方法调整参数降低错误率。默认参数如下:
key #指定存储元素的键,若已经存在,则bf.reserve会报错 error_rate=0.01 #表示错误率 initial_size=100 #表示预计放入布隆过滤器中的元素数量
当放入元素数量超过 initial_size 时,错误率会升高。因此需设置较大的 initial_size 避免错误率上升。错误率越低,所需空间越大,应尽可能精确估算元素数量,避免空间浪费。根据业务场景确定可接受的错误率范围。
自定义过滤器创建与注意事项
使用自定义参数需在 add 操作前显式创建 key:
client.execute_command("bf.reserve", "keyname", 0.001, 50000)布隆过滤器相比列表、散列、集合等结构占用空间更少、效率更高,但结果具有概率性。理论上添加元素越多,误报可能性越大。此外,存放于布隆过滤器中的元素不易删除,因为可能误删其他元素。
