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 会:
- 通过路径查找 dentry 缓存
- 找不到就去磁盘读目录项,加载到 dentry 缓存
- 通过 dentry 找到 inode
- 创建 file 对象,返回文件描述符
避坑指南:我曾经遇到一个性能问题——大量小文件操作时 dentry 缓存被撑爆,导致系统响应变慢。解决方案是调整 /proc/sys/vm/drop_caches 或增大 dentry 缓存上限。别轻易在生产环境清缓存,最好先观察。
下面这张图展示了 VFS 如何桥接上层应用和底层文件系统:
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(但做好备份)
嗯,这一章就到这里。记住:没有完美的文件系统,只有最适合你场景的选择。