Skip to main content

布隆过滤器容量不够用如何解决?

作者:程序员马丁

在线博客:https://nageoffer.com

note

热门项目实战社群,收获国内众多知名公司面试青睐,近千名同学面试成功!助力你在校招或社招上拿个offer。

回答话术

当系统运行过程中,布隆过滤器中的元素逐渐追平或超过设置的元素数量,就会引起误判率增加的风险。

为此,我们需要一种预警以及容量不够用的解决方案。我觉得可以通过定时任务扫描布隆过滤器的容量,判断当前容量距离最初设置峰值差量还有多少。

假如设置阈值是 20%,当布隆过滤器中元素满 80% 以上后,就触发告警发邮件或其它通信工具。然后人为或程序操作拉起一个新的布隆过滤器,新布隆过滤器的容量建议为旧容量的 1.5 倍,以此解决布隆过滤器容量问题。

因为布隆过滤器并没有数据同步方法,所以历史数据需要从源表(可能是 MySQL 等数据源)中重新读区并写入到新布隆过滤器。

问题详解

虽然看着上面的思路以及解决方案没有问题,但是如果要实现,需要具备一些细节难点知识。

1. 如何判断布隆过滤器的容量达到阈值?

Redisson 布隆过滤器 RedissonBloomFilter 实现类中有一个 count 方法,返回的是新增到布隆过滤器的数据。

image.png

看到这里你是否会感到疑惑,布隆过滤器这样一个位数组,通过 Hash 新增和查询,怎么可能会有数据统计的功能?

这是因为布隆过滤器底层结构是 BitMap,BitMap 是可以通过 BITCOUNT 命令统计元素数量。

2. 如何把历史数据快速同步到新布隆过滤器?

针对大数据量查询,我们可以使用 select * from table where id > xxx limit xxx; 每次查处一批数据后,把最大的 id 当作查询条件赋值给下一次查询。通过这种方式不断循环,直到查出全部数据并放到新布隆过滤器。

为什么不使用常规 limit xx xx?因为这会存在深分页问题,在大数据量场景下,分页越是到后面越是容易形成性能深渊。

另外,同步到 Redis 新布隆过滤器中会涉及到大量的网络 IO 操作,尽量使用管道命令节省性能。

Redis 管道文章参考:✅ 如何提升 Redis 批量访问性能?

3. 定时任务多久执行一次合适?

针对这种较为重要的判断,可以适当让扫描周期密集些,比如 1-5 分钟执行一次。触发设定阈值后,发起报警。

4. 如何在代码中替换新旧布隆过滤器?

我们可以假设布隆过滤器从初始就是两个,可以通过一个布尔类型的变量判断使用哪个布隆过滤器。

伪代码如下:

public RBloomFilter<String> getActualBloomFilter() {
return bloomFilterFlag ? oldBloomFilter : newBloomFilter;
}

通过配置中心控制 bloomFilterFlag 参数,即可实现不停机更新。

另外,如果新的布隆过滤器容量又不够了,那我们只需要将旧布隆过滤器删掉重新创建一个更大的,再修改下 bloomFilterFlag 就可以无缝实现该功能。