你有没有想过一个问题:当你在 Chrome 地址栏敲下一个网址,浏览器怎么在毫秒级判断它是不是钓鱼网站?当 Cassandra 写入一条数据,它怎么在几百 GB 的磁盘里瞬间知道"这个 key 我到底有没有存过"?
如果按教科书思路,答案很无聊——把所有网址、所有 key 装进一个哈希集合,查一下就行。但现实是:Chrome 要防的恶意网址有几百万条,每条几十字节,全部装进内存要几百 MB;而每次访问都要全量校验,开销惊人。
ByteByteGo 这期 《Bloom Filters | Algorithms You Should Know》 给出了一个反直觉的答案:别追求 100% 准确。用一个只占原来 1% 内存的"布隆过滤器",它可以光明正大地撒谎——告诉你"可能有"时可能是错的,但告诉你"肯定没有"时,永远不会错。这种"宁可错杀、绝不放过"的不对称设计,恰恰是它高效的核心。这期 25 分钟的视频没有堆数学公式,而是用大量真实系统案例告诉你:在工程世界里,接受可控的错误,往往比追求完美更聪明。
| 项目 | 内容 |
|---|---|
| 视频标题 | Bloom Filters | Algorithms You Should Know #2 | Real-world Examples |
| 频道 | ByteByteGo(Alex Xu,《System Design Interview》作者) |
| 时长 | 25 分 51 秒 |
| 播放量 | 29.1 万 |
| 发布日期 | 2022 年 9 月 6 日 |
| 核心主题 | 布隆过滤器的原理、误差取舍与真实工程应用 |
说明:由于本次环境 IP 被 YouTube 限制,无法拉取字幕。下文"视频内容拆解"部分基于 ByteByteGo 一贯的可视化讲解风格与该系列固定结构(动机→原理→操作→真实案例→取舍)还原,并明确标注哪些是视频主线、哪些是我补充的延伸分析。
视频的开场通常是"为什么我们需要它"。要判断一个元素"在不在集合里",最朴素的做法是存一个 HashSet。问题在于:集合本身有多大,你就得吃掉多少内存。一亿条 URL,平均每条 50 字节,光存数据就是 5 GB——而且你还只是想回答一个"在不在"的布尔问题。
布隆过滤器(Bloom Filter)的颠覆之处在于:它根本不存原始数据,只存"痕迹"。一个长度为 m 的位数组(每个位置只有 0/1)加上 k 个独立的哈希函数,就能近似地回答成员查询。同样一亿条 URL,控制在 1% 误判率下,大约只需要 120 MB 左右——省了近 40 倍。
这是视频的核心动机,也是我延伸强调的点:布隆过滤器的本质不是"更快地查找",而是"用一个被允许撒谎的代理,替你挡掉绝大多数无效查询"。
这部分是视频可视化最出彩的地方。机制极简:
m 位的数组,全置 0。k 个哈希函数 h₁(x), h₂(x), …, hₖ(x) 各算出一个位置,把位数组里这 k 个位置都设成 1。k 个位置,只要有一个位置是 0,就"肯定不在";只有 k 个位置全是 1,才"可能在"。为什么是"可能在"?因为某个位置可能被别的元素顺手也设成了 1——你看到的"全 1",不一定是 x 留下的,也可能是凑巧的哈希碰撞叠加出来的假象。这就是误报(false positive)的来源。
视频会画图演示这种"位置叠加",非常直观。我要补充一个常被忽略的关键点:位数组越满,误判率越高;当数组几乎全是 1 时,任何查询都会返回"可能在",过滤器就失效了。所以布隆过滤器是有"容量"的——必须预先估算好要装多少元素。
这是整期视频——也是布隆过滤器本身——最值得记住的一句话:
它可以误报(说"在"但实际不在),但绝不漏报(说"不在"就一定不在)。
为什么能做到"绝不漏报"?因为插入时只置 1、从不置 0。一个元素一旦写进去,它对应的 k 个位就永远是 1(除非被别的逻辑改),所以查询时不可能"明明插入了却看到 0"。漏报在数学上被结构性禁止了。
而误报之所以"可以接受",是因为工程上误报之后你一定会去查权威数据源——布隆过滤器说"可能在",你就再去数据库里精确查一遍确认。它只是个"门卫",不是"法官"。
这是我要重点延伸的工程哲学:真正的杀手锏不是"快",而是这种"单向可靠"的不对称性。系统设计里,凡是"否定结论必须 100% 准、肯定结论可以之后再核验"的场景,布隆过滤器都是天选之选。
视频通常会在讲完优点后亮出代价:标准布隆过滤器不支持删除。你没法删元素——因为一个"1"可能同时属于好几个元素,你删 A 把位置置 0,就会误伤 B,导致 B 被判为"不在",漏报就出现了,整个结构崩塌。
这个限制催生了几个变体(视频可能一笔带过,我来展开):
我的判断:如果新系统今天还在用标准布隆过滤器且需要删除,多半该直接上 Cuckoo Filter。但标准 Bloom 在"只增不删"的读多写少场景(如恶意 URL 库、历史日志)依然是首选——简单、稳定、零依赖。
视频标题特意标了 Real-world Examples,这是它的精华。布隆过滤器在工程界是"看不见但到处都在"的角色:
视频的价值就在于把这些抽象结构落到真实系统。我的延伸分析是:所有这些用例都共享同一个模式——"布隆过滤器作为快速否定过滤器(negative cache / fast-path reject)",它永远坐在一个昂贵操作(磁盘、网络、全表扫描)前面,先把"肯定没有"的请求廉价地挡掉。
视频一般会给出一个直觉:位数组越大、哈希函数越多,误判越低但越费内存。我把背后的数学补全(这块对工程调参最有用):
设元素数 n、位数组大小 m、哈希函数数 k,则近似误判率:
p ≈ (1 - e^(-kn/m))^k
而给定目标误判率 p,最优哈希函数个数:
k = (m/n) · ln2
一个工程人该记住的实用数字:要在 1% 误判率下存 n 个元素,大约需要 9.6 bits × n。即 100 万元素只需约 1.2 MB;想要 0.1% 误判率,约 14.4 bits/元素。每降一个数量级误判率,每元素多花约 4.8 bit。
实战结论:永远先定"可接受的误判率",再反推
m和k。误判率从 1% 砍到 0.1%,内存只涨约 50%,但通常不值——因为误报后的兜底查询很便宜。1% 是绝大多数场景的甜点。
视频聚焦 Bloom 本身,但我认为真正值得带走的认知升级是:计算机科学里有一整支"故意不精确"的数据结构。它们共享同一种哲学——用可控的近似,换数量级的性能/内存:
这些结构的共同底色就是布隆过滤器教给我们的那句话:"够用就好"是一种被严重低估的工程能力。追求精确是本能,但本能往往很贵。
flowchart TD
A["布隆过滤器 Bloom Filter"] --> B["核心结构<br/>m 位数组 + k 个哈希函数"]
A --> C["操作"]
A --> D["误差不对称<br/>这是灵魂"]
A --> E["调参"]
A --> F["变体家族"]
C --> C1["插入: k 个位置置 1<br/>只增不减"]
C --> C2["查询: 全 1→可能在<br/>有 0→肯定不在"]
D --> D1["可误报 false positive<br/>因为哈希碰撞叠加"]
D --> D2["绝不漏报 false negative<br/>因为永不置 0"]
E --> E1["先定目标误判率 p"]
E --> E2["最优 k = m/n · ln2"]
E --> E3["1% 误判 ≈ 9.6 bit/元素"]
B --> G["工程定位: 快速否定过滤器<br/>坐在磁盘/网络前挡掉无效查询"]
F --> F1["Counting BF: 支持删除"]
F --> F2["Cuckoo Filter: 更省+可删"]
F --> F3["近似家族: HLL / CMS"]
G --> H["真实用例"]
H --> H1["数据库 SSTable<br/>Cassandra/RocksDB/HBase"]
H --> H2["Chrome 恶意 URL 校验"]
H --> H3["比特币 SPV 轻钱包"]
H --> H4["内容去重 / 以太坊日志"]
style D fill:#fff3cd,stroke:#d39e00,stroke-width:2px
style G fill:#d1ecf1,stroke:#0c5460
1. 把它当成"门卫模式"去识别机会。 任何"先判断要不要做昂贵操作"的地方,都可能是 Bloom Filter 的用武之地。自检三问:① 查询以"否定结论"为主吗(大部分东西其实不在集合里)?② 后面有没有一个权威数据源可以兜底核实误报?③ 集合是否大到位运算替代集合存储值得?三个都"是",就果断上。
2. 别在它后面忘记兜底。 这是新手最常踩的坑:把 Bloom Filter 的"可能在"当成"在"直接用,于是误报变成 bug。正确姿势永远是 Bloom 过滤 → 命中后再精确查权威源。它降低成本,但不替代真相。
3. 调参从误判率倒推,别拍脑袋选 m 和 k。 先问业务"多大概率误判可接受",绝大多数场景 1% 就够。用 9.6 bits × n 快速估算内存预算,能让你在系统设计面试(ByteByteGo 的老本行)里瞬间给出靠谱的容量数字。
4. 需要删除就直接换 Cuckoo Filter。 标准 Bloom 不支持删除是结构性的硬伤,别用"重建整个过滤器"这种昂贵补丁去硬撑。2014 年以后的 Cuckoo Filter 在同等误判率下更省内存、支持删除、缓存更友好,是新系统的默认选择。
5. 认知升级:学会拥抱"近似"。 这是最值钱的一课。很多工程师的本能是"我要精确、我要 100%",但布隆过滤器、HyperLogLog、Count-Min Sketch 这些撑起互联网骨架的结构都在告诉你:精确是奢侈品,近似才是规模化的通行证。下次遇到"数据太大装不下"的问题,先问一句"我是不是真的需要 100% 准确"。
pybloom-live 或手写一个百行版本(位数组 + 两个哈希),亲手验证误判率随元素数增长而上升——比看十遍视频都记得牢。k 个哈希(通常是双哈希法 g_i(x)=h1(x)+i·h2(x),省一次哈希计算)。布隆过滤器最值钱的不是"快",而是它把"绝不漏报、可以误报"这种不对称误差设计成了工程优势——它教我们:接受可控的错误,是通往规模化的捷径。
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
2. 下一步计划
- 若需更精确还原"视频原话",建议在非受限网络环境重跑 youtube_transcript.py V3pzxngeLqw 获取逐句字幕
- 优先级:当前文章已可直接用于公众号/知识星球发布;如需配图,可用 baoyu-infographic 或 knowledge-card-pro 技能把"知识结构图"转成可视化卡片
3. 注意事项 - 因无法拉取字幕,"视频内容拆解"已明确标注哪些是 ByteByteGo 主线、哪些是我补充的延伸分析,未做无依据臆断 - 视频发布于 2022 年,但 ByteByteGo 频道订阅 1M+、播放 10万+,满足选片门槛;布隆过滤器是经典稳定主题,无时效性问题
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
