4. 文件系统原理:inode与block机制、VFS虚拟文件系统层、常见文件系统对比

文件系统这东西,说白了就是硬盘上的「档案管理员」。你存个文件,它得知道放哪、怎么找、碎片怎么处理。我刚开始搞存储时,觉得文件系统就是个格式化工具,直到有一次线上服务器因为 inode 耗尽挂了——明明硬盘还有几十 G 空间,就是写不进文件。嗯,从那以后我再也不敢小看 inode 了。

4.1 inode 与 block:文件存储的「户口本」和「货架」

每个文件在磁盘上由两部分组成:inode 和 block。你可以把 inode 想象成文件的「户口本」,block 就是实际放数据的「货架」。

4.1.1 inode 里存了什么?

inode 不存文件名,它存的是文件的元数据。我见过不少新手以为文件名在 inode 里,其实文件名在目录项里。inode 记录的是这些:

  • 文件类型(普通文件、目录、符号链接等)
  • 权限(rwx 那一套)
  • 所有者 UID / GID
  • 文件大小
  • 时间戳(atime、mtime、ctime)
  • 数据块指针(指向实际 block 的地址)
  • 引用计数(硬链接数)

关键点:inode 数量在格式化时就固定了。你可以在 mkfs.ext4 时用 -N 或 -i 参数调整 inode 密度。我建议小文件多的场景(比如邮件服务器)加大 inode 数量,否则你会遇到「空间有余、inode 不足」的尴尬。

4.1.2 block 怎么分配?

block 是磁盘读写的最小单位。ext4 默认 block 大小是 4096 字节(4K)。一个 1 字节的文件,也要占一个 block。你想想看,如果存 100 万个 1 字节的小文件,光 block 浪费就接近 4GB。

block 分配策略各文件系统不同:

  • ext4:使用多块分配器(mballoc),尽量一次分配连续 block
  • XFS:使用延迟分配(delayed allocation),先缓存再一次性写入
  • Btrfs:使用 COW(写时复制),每次修改都分配新 block

我的经验:数据库服务器建议用 XFS,它的延迟分配能减少碎片。我曾经帮一个电商平台调优,把 ext4 换成 XFS 后,数据库写入延迟降低了 15%。

4.1.3 查看 inode 和 block 信息

# 查看文件 inode 号
$ ls -li testfile
1234567 -rw-r--r-- 1 root root 1024 Apr 10 10:00 testfile

# 查看文件系统 inode 使用情况
$ df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/sda1      655360  123456  531904   19% /

# 查看 block 大小
$ stat -f / | grep "Block size"
Block size: 4096

4.2 VFS 虚拟文件系统层:统一接口的「翻译官」

Linux 能同时挂载 ext4、XFS、Btrfs、NTFS,靠的就是 VFS。它定义了一套通用接口,让上层应用不用关心底层文件系统是什么。

VFS 的核心对象有四个:

对象 作用 对应结构体
超级块 描述整个文件系统(总大小、状态、操作函数表) super_block
inode 描述单个文件或目录的元数据 inode
dentry 目录项,维护文件名到 inode 的映射 dentry
file 打开文件后的实例,记录读写位置、权限等 file

你执行 open() 系统调用时,VFS 会:

  1. 通过路径查找 dentry 缓存
  2. 找不到就去磁盘读目录项,加载到 dentry 缓存
  3. 通过 dentry 找到 inode
  4. 创建 file 对象,返回文件描述符

避坑指南:我曾经遇到一个性能问题——大量小文件操作时 dentry 缓存被撑爆,导致系统响应变慢。解决方案是调整 /proc/sys/vm/drop_caches 或增大 dentry 缓存上限。别轻易在生产环境清缓存,最好先观察。

下面这张图展示了 VFS 如何桥接上层应用和底层文件系统:

VFS 虚拟文件系统层架构 用户态应用(open/read/write) 系统调用接口(sys_open / sys_read) VFS 核心层 super_block inode dentry file 具体文件系统实现 ext4 操作函数表 XFS 操作函数表 Btrfs 操作函数表 块设备层(Block I/O) VFS 通过统一的操作函数表,让上层应用无需关心底层是 ext4、XFS 还是 Btrfs

4.3 常见文件系统对比:ext4 vs XFS vs Btrfs

这三个是目前 Linux 上最主流的文件系统。我根据实际项目经验,给你列个对比表:

特性 ext4 XFS Btrfs
最大文件大小 16 TB(4K block) 8 EB 16 EB
最大文件系统大小 1 EB 8 EB 16 EB
日志模式 ordered / writeback / journal 元数据日志 COW + 日志
碎片整理 支持(e4defrag) 支持(xfs_fsr) 支持(btrfs filesystem defrag)
快照 不支持 不支持(需 LVM) 原生支持
压缩 不支持 不支持 支持(zlib / lzo / zstd)
RAID 支持 需 mdadm 需 mdadm 原生 RAID 0/1/5/6/10
在线扩容 支持 支持 支持
在线缩容 不支持 不支持 支持
适用场景 通用服务器、嵌入式 大文件、数据库、高性能计算 容器、快照需求、实验环境

4.3.1 ext4:稳如老狗

ext4 是 ext3 的升级版,兼容性好,几乎任何 Linux 发行版都支持。我个人习惯在系统盘和 /boot 分区用 ext4,因为它的 fsck 工具最成熟,出问题好修。

但 ext4 有个硬伤——不支持快照和压缩。如果你需要频繁做快照,得搭配 LVM 使用。

4.3.2 XFS:大文件之王

XFS 是 SGI 开发的,64 位文件系统,对大文件和大容量场景优化极好。我建议数据库、视频存储、高性能计算用 XFS。它的延迟分配策略能显著减少碎片。

注意:XFS 的 fsck 速度很慢,因为要扫描整个元数据树。我遇到过 50TB 的 XFS 文件系统,fsck 跑了 6 个小时。所以生产环境一定要做好监控,别等出问题再 fsck。

4.3.3 Btrfs:功能最全但争议最大

Btrfs 是 COW 文件系统,原生支持快照、压缩、RAID、校验和。听起来很完美,对吧?但我在项目中踩过不少坑:

  • RAID 5/6 有写漏洞(write hole),官方建议谨慎使用
  • 碎片问题比 ext4 和 XFS 严重,需要定期 defrag
  • 极端情况下(比如突然断电)恢复难度大

不过话说回来,Btrfs 的快照和回滚功能确实好用。我曾在测试环境用 Btrfs 做系统更新回滚,一条命令就搞定,比 ext4 + LVM 快多了。

我的建议:生产环境核心业务用 ext4 或 XFS,Btrfs 适合容器存储、测试环境或非关键数据。别把鸡蛋放一个篮子里——我见过有人把整个数据中心都跑在 Btrfs 上,结果一次内核 bug 导致数据损坏,恢复起来欲哭无泪。

4.4 小结

inode 和 block 是文件系统的地基,VFS 是让不同文件系统和平共处的桥梁。选文件系统时,别只看功能列表,要结合你的业务场景:

  • 小文件多 → ext4(调大 inode 密度)
  • 大文件多 → XFS
  • 需要快照/压缩 → Btrfs(但做好备份)

嗯,这一章就到这里。记住:没有完美的文件系统,只有最适合你场景的选择。