外部存储结构:外排序、倒排索引与 LSM Tree

学了这么多数据结构之后,如果一直停留在“数据都能放进内存里”的想象里,视角其实还是不够完整。真实系统里,很多真正有挑战的问题,都发生在数据规模远超内存的时候:

  • 日志量特别大;
  • 索引体积很大;
  • 搜索和存储都要依赖磁盘;
  • 一次访问的成本不再是 CPU 比较,而是磁盘 I/O。

这时,数据结构设计的重点就会发生明显变化。外部存储结构之所以重要,就在于它提醒我们:

当内存不再是唯一主战场,结构设计必须围绕块访问、顺序 I/O、批量写入和磁盘友好性重新考虑。

这一篇不准备把外存系统细节讲得过重,而是先从数据结构视角,把三类非常有代表性的外部存储相关结构思路串起来:外排序、倒排索引和 LSM Tree。它们虽然用途不同,但都在回答同一个问题:大规模数据怎样在外存上组织得更高效。

一、为什么外部存储问题和内存数据结构不一样

在内存结构里,我们习惯了:

  • 随机访问代价低;
  • 指针跳转相对便宜;
  • 结构细粒度调整成本可控。

但在外存里,真正昂贵的通常是:

  • 一次磁盘寻址;
  • 一次随机 I/O;
  • 把很多小写操作零散地刷到磁盘。

所以外存结构通常更重视:

  • 顺序读写;
  • 块级访问;
  • 批量合并;
  • 降低随机 I/O 次数。

这就是为什么 B+ 树、LSM Tree 这种结构会和内存中的红黑树风格明显不同。

二、什么是外排序

外排序可以理解成:

当数据量大到内存放不下时,借助磁盘分批读写完成排序的过程。

如果数据完全在内存里,排序算法我们已经见过很多;但当数据太大时,就不能直接一次性加载全部元素。这时通常会采用两阶段思路:

  • 先把数据分块读入内存,各自排序后写回磁盘;
  • 再对这些有序块做多路归并。

所以外排序的核心不是“发明新排序顺序”,而是:

让排序过程适配“数据放不下、I/O 很贵”的现实。

三、外排序为什么通常依赖多路归并

因为多路归并特别适合顺序 I/O。

如果你已经有多个磁盘上的有序段,那么:

  • 顺序读取每段的当前头部;
  • 选出最小元素写入输出;
  • 再继续推进对应段;

就能把多个大文件逐步归并成更大的有序结果。

而且归并过程可以很好地利用缓冲区和顺序读取,避免过多随机磁盘访问。

四、什么是倒排索引

倒排索引是搜索系统里最典型的数据结构之一。它的核心思想可以理解成:

不是记录“文档包含哪些词”,而是记录“某个词出现在哪些文档中”。

例如:

  • data 出现在文档 1、3、8;
  • structure 出现在文档 2、3、5;

那么搜索某个词时,就可以直接定位到对应文档集合。

这之所以叫“倒排”,是因为它把原本“文档 -> 词”的方向反了过来,变成了“词 -> 文档列表”。

五、为什么倒排索引特别适合搜索

因为搜索引擎最常做的事情不是“遍历所有文档看谁包含关键词”,而是:

  • 给定关键词;
  • 迅速拿到候选文档集合;
  • 再做交集、排序、打分。

如果没有倒排索引,每次搜索都得扫描全部文本,这在大规模系统里根本无法接受。

所以倒排索引本质上是:

为“按词找文档”这个操作量身定制的索引结构。

六、倒排索引和 Trie / 哈希表有什么关系

倒排索引本身通常由两部分组成:

  • 词典;
  • 倒排列表。

而词典层可以用:

  • 哈希表;
  • B+ 树;
  • Trie;

等结构去维护。也就是说,倒排索引不是脱离已有结构的新世界,而是把很多基础结构组合到搜索场景里的一种组织方式。

七、什么是 LSM Tree

LSM Tree,全称通常是 Log-Structured Merge Tree。它是现代存储系统和数据库里非常经典的一种结构,尤其适合写多读多、磁盘友好的场景。

它最核心的思想可以概括成:

先把写入集中落到内存和顺序磁盘文件中,再通过后台合并,把多个有序段逐步整理起来。

也就是说,它不像 B+ 树那样总在原位置做更新,而是更偏向:

  • 先积累;
  • 再批量刷盘;
  • 再定期合并。

八、LSM Tree 为什么适合高写入场景

因为它尽量避免随机写磁盘。

典型思路通常是:

  • 新写入先进入内存表;
  • 内存表满了,再顺序刷成一个磁盘上的有序文件;
  • 磁盘上逐渐形成多个有序层;
  • 后台再做合并压缩。

这样做的好处是:

  • 把很多离散小写操作转成顺序大写;
  • 显著提升写入吞吐;
  • 很符合现代 SSD / 磁盘系统的 I/O 特性。

九、LSM Tree 的代价是什么

它不是没有代价。典型代价包括:

  • 查询时可能要查多个层级 / 多个文件;
  • 删除通常是逻辑删除,再靠后续 compaction 真正清理;
  • 后台合并本身会带来额外 I/O 和写放大。

所以 LSM Tree 的本质是一种非常典型的工程权衡:

  • 牺牲一部分读路径简单性;
  • 换来非常强的写入友好性。

十、外排序、倒排索引和 LSM Tree 的共同点是什么

表面上它们分别属于排序、搜索、数据库存储,但从数据结构视角看,它们其实有共同逻辑:

  • 都要面对“数据量太大,无法只靠内存”;
  • 都要围绕磁盘 I/O 重新设计组织方式;
  • 都更重视顺序访问、批量处理和索引结构;
  • 都不是简单把内存结构搬到磁盘,而是重新适应外存特性。

这就是外部存储结构最值得建立的认识。

十一、学习外部存储结构时最容易踩的坑

1. 只从内存复杂度看问题

在外存场景里,I/O 次数往往比单纯比较次数更重要。

2. 把 B+ 树、LSM Tree、倒排索引看成互相替代

它们常常服务的目标并不相同。

3. 不了解顺序 I/O 和随机 I/O 差异

这是理解外存结构设计的关键背景。

4. 误以为外部结构只是“数据更大而已”

其实设计哲学都变了。

总结

外部存储结构的重要性,不只是因为它们对应更大的数据量,而是因为它们迫使你真正从“内存友好”切换到“磁盘友好”的视角。真正值得先建立起来的,是这些核心认识:

  • 外存数据结构关注的核心通常是块访问、顺序 I/O 和批量处理;
  • 外排序用分块排序加多路归并解决“大到内存放不下”的排序问题;
  • 倒排索引把“词 -> 文档列表”作为核心组织方向,是搜索系统的基础结构;
  • LSM Tree 通过先写内存、后顺序刷盘、再后台合并的方式优化写入;
  • 这些结构都说明:数据结构设计必须服从存储介质的物理特性;
  • 真正学会这一篇,不是记住几个名词,而是意识到“当数据上磁盘后,结构设计的优先级已经完全变了”。

把这一篇理解透之后,后面再去学并发结构和工程实践时,你会更容易把数据结构和真实系统联系起来,而不只是停留在内存模型的抽象世界里。

参考资源