第 41 章 局部性和快速文件系统

老 UNIX 文件系统的问题

老 UNIX 文件系统将磁盘视为随机存取内存,未考虑磁盘定位成本,导致性能极差(仅提供总磁盘带宽的 2%)。主要问题包括:

  • 数据分散:文件数据块与 inode 距离远,读取时会产生昂贵的寻道开销。
  • 碎片化 (Fragmentation):空闲空间缺乏管理,文件数据在磁盘上不连续。
  • 块大小过小:512 字节的原始块大小导致数据传输效率低下。

FFS 的核心理念:磁盘意识

伯克利团队开发的快速文件系统 (Fast File System, FFS) 引入了“磁盘意识”,在保持原有 API 接口(如 open(), read(), write())不变的前提下,通过改变内部结构和分配策略来提升性能。

组织结构:柱面组 (Cylinder Group)

FFS 将磁盘划分为多个柱面组(现代文件系统如 ext2/ext3 称为块组)。通过将相关文件放置在同一组中,避免长距离寻道。

每个柱面组包含:

  • 超级块副本:用于容灾,若主超级块损坏仍可挂载文件系统。
  • inode 位图 (ib) 和数据位图 (db):记录组内 inode 和数据块的分配状态,便于寻找大块连续可用空间。
  • inode 区域与数据块区域

分配策略

FFS 的核心分配原则是“相关的数据放一起,无关的数据分开放”。

  • 目录分配:选择已分配目录少且空闲 inode 多的柱面组,以平衡跨组的目录分布并为后续文件分配预留空间。
  • 文件分配
    • 将文件的数据块与其 inode 分配在同一个柱面组中。
    • 将同一目录下的所有文件分配在同一个柱面组中。

大文件例外策略

若不加限制,大文件会填满整个块组,破坏其他相关文件的局部性。FFS 采用以下策略处理大文件:

  • 前 12 个直接块与 inode 放在同一组。
  • 后续的每个间接块及其指向的数据块,分配到不同的块组中。
  • 摊销 (Amortization):通过增加每次寻道后传输的大块大小(如 4MB),确保大部分时间用于数据传输而非寻道,从而逼近磁盘的峰值带宽。

FFS 的其他优化与改进

  • 子块 (Sub-block):为解决 4KB 块存储小文件带来的内部碎片问题,FFS 引入 512 字节的子块。结合 libc 的写缓冲机制,兼顾了空间效率与 I/O 性能。
  • 参数化布局:针对早期磁盘,FFS 通过跳跃式扇区布局(交错布局)避免连续读取时的额外旋转延迟(现代磁盘已通过内部的磁道缓冲区解决此问题)。
  • 可用性改进:引入长文件名、符号链接(可跨卷、可指向目录)以及原子化的 rename() 操作,极大提升了系统的可用性。