10亿条URL的黑名单,如何快速判断一个新请求的URL是否在黑名单内?

📅 2026/7/12 15:45:10 👁️ 阅读次数 📝 编程学习
10亿条URL的黑名单,如何快速判断一个新请求的URL是否在黑名单内?

在日常开发中,你是否遇到过这样的场景:

有一个包含10亿条URL的黑名单,如何快速判断一个新请求的URL是否在黑名单内,同时避免占用几十GB的内存?

在我们学习缓存三剑客时,关于缓存穿透,我们常用的解决方案之一是什么?

这些问题的核心,都是对海量数据的存在性判断,我们不需要获取数据本身,只需要知道“在”或“不在”,而布隆过滤器(Bloom Filter),就能很好地解决这个问题。

一、布隆过滤器是什么?

是一种空间高效的概率型数据结构,核心作用是快速判断一个元素是否存在于一个集合中。

布隆过滤器主要由两部分组成,

一部分是初始值都为 0 的位图数组,

一部分是N 个哈希函数。

布隆过滤器不存储数据本身,只存储数据的哈希标记。当我们往数据库中写数据时,顺便在布隆过滤器中做个标记,这样下次查数据时,只要查布隆过滤器,查的数据没有标记的话,那说明数据库里也没有。

那既然这么说了,查布隆过滤器一定很快吧?确实很快。查询布隆过滤器的时间复杂度O(k),k是哈希函数个数,通常是个位数,效率很高。

二、布隆过滤器是怎么工作的?

布隆过滤器的底层结构很简单,只有两个核心组件:

一个固定长度的位图数组(初始值都为0),

一组独立的哈希函数,

所有逻辑都围绕这两个组件展开。

接下来举个例子:

假设我有一个布隆过滤器,数组初始长度为8,哈希函数个数为3

当我们插入元素“bloom”时,步骤如下:

  1. 将“bloom”传入3个哈希函数,得到3个不同的哈希值;

  2. 然后再把这 3 个哈希值对 8 取模

  3. 将得到的结果在数组中的相应位置置1,比如取模得到1,3,5 那就1,3,5位置1 (总共0-7)

这样一通操作之后,以后当我们要查询"bloom"是否在数据库中时,只需要通过布隆过滤器查第1,3,5位置是否全为1,必须全为1才可能行,只要有一个0都说明“bloom”不在数据库中。

那为什么是可能行呢?

因为不同的数经计算得到的哈希值对8取模结果可能是一样的,可能存在哈希冲突。那这样明明数据库中没有这个数,我却算出了它1,3,5位也是1,这就判断错误了。

三、使用布隆过滤器解决缓存穿透

这里就回到了开头的缓存三剑客中的缓存穿透了。

发生缓存穿透原因是因为用户请求一个不存在的数据,此数据在缓存和数据库中都不存在。

这是我们可以用布隆过滤器存储所有已存在的key,请求过来时,先查布隆过滤器,如果返回“绝对不存在”,那就直接返回空结果,不访问缓存和数据库。如果返回“可能存在”,再查缓存和数据库。这样就能拦截99%以上的无效请求,保护数据库。

四、布隆过滤器的其它应用

1. 海量数据去重

比如爬虫去重:爬取网页时,需要记录已爬取的URL,避免重复抓取。如果用哈希表存储,1亿条URL会占用几十GB内存,而用布隆过滤器,仅需几十MB内存就能搞定,完美解决空间瓶颈。

类似场景还有:邮件黑名单去重、用户ID去重、日志去重等。

2. 数据库索引优化

HBase、LevelDB、RocksDB等数据库引擎,会用布隆过滤器判断目标键是否存在于某个SSTable文件中,避免不必要的磁盘IO操作,提升查询性能——如果布隆过滤器判断键不存在,就无需读取磁盘文件,直接返回空结果。

3. 分布式系统中的数据校验

比如分布式缓存中,判断一个key是否在其他节点的缓存中;区块链轻节点中,判断某个交易是否可能包含在区块中,减少数据同步的开销。

五、总结

布隆过滤器的本质,是“用极小的空间成本,换取极高的查询效率,同时接受轻微的误判”。它不适合所有场景,但在海量数据的存在性判断中,是无可替代的工具。

如果觉得这篇博客对你有帮助,欢迎点赞~收藏~评论~