常见文件系统格式详解 — FAT 到 ZFS 的进化史 / Filesystem Formats from FAT to ZFS
📅 创建时间:2026-06-17 🏷️ 标签:#文件系统 #FAT32 #NTFS #ext4 #btrfs #XFS #ZFS 📚 前置知识:[[04-filesystem-concepts]]
📋 本章目标
- 理解 FAT32 的极简结构——为什么它 40 岁了还在用
- 掌握 NTFS 的 MFT 主文件表设计——一切皆文件的 Windows 实现
- 掌握 ext4 的 extent tree 和延迟分配——Linux 默认文件系统为什么"稳"
- 理解 btrfs 的 COW 和 subvolume——下一代文件系统的野心
- 了解 XFS 和 ZFS 的定位——何时该用它们
- 建立选型判断力——什么场景选什么文件系统
第1部分:FAT32 — 极简主义的胜利
1.1 为什么 FAT32 今天还在用
┌─────────────────────────────────────────────────────────────┐
│ FAT32 的典型应用场景 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 你在下列设备上 100% 会遇到 FAT32: │
│ │
│ • U 盘(出厂默认格式) │
│ • SD 卡 / microSD(相机、树莓派) │
│ • EFI 系统分区(ESP)—— UEFI 固件唯一保证能读的格式 │
│ • 游戏机存储卡 (Switch/3DS) │
│ • 车载音响/电视的 USB 口 │
│ │
│ 原因: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 结构足够简单 → 任何设备都能实现驱动 │ │
│ │ 2. 无专利负担 → 免费使用 │ │
│ │ 3. exFAT 有微软专利 → 直到 2019 年才进入 Linux 内核 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1.2 FAT32 的数据结构
┌─────────────────────────────────────────────────────────────┐
│ FAT32 的磁盘布局 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌───────────────┐ ┌─────────────────────────┐│
│ │ 保留区 │ │ FAT 表 #1 │ │ FAT 表 #2 (备份) ││
│ │(含BPB) │ │ (簇链) │ │ ││
│ └──────────┘ └───────────────┘ └─────────────────────────┘│
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 数据区 (簇) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 簇 2 │ │ 簇 3 │ │ 簇 N │ │ │
│ │ │ 根目录 │ │ 普通文件 │ │ ... │ │ │
│ │ │ 数据 │ │ 数据 │ │ │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ BPB (BIOS Parameter Block) — FAT32 的"超级块": │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 每扇区字节数 (512/4096) │ │
│ │ • 每簇扇区数 (1/2/4/8/16/32/64) │ │
│ │ • 保留扇区数 │ │
│ │ • FAT 表数量 (通常 2) │ │
│ │ • 卷标 (11 字节) │ │
│ │ • 文件系统类型字符串 ("FAT32 ") │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ FAT 表 — 文件系统的核心(名叫"文件分配表"): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ FAT[0] FAT[1] FAT[2] FAT[3] FAT[4] FAT[5] │ │
│ │ ────────────────────────────────────────────── │ │
│ │ 保留 保留 0xFFFF 0x0004 0x0005 0xFFFF │ │
│ │ ↑ EOF ↑下一个 ↑下一个 ↑ EOF │ │
│ │ 簇 4 簇 5 │ │
│ │ │ │
│ │ 读一个文件: │ │
│ │ 1. 目录项告诉你起始簇号 (如簇 3) │ │
│ │ 2. 读 FAT[3] = 4 → 下一个簇是 4 │ │
│ │ 3. 读 FAT[4] = 5 → 下一个簇是 5 │ │
│ │ 4. 读 FAT[5] = 0xFFFF → 文件结束 │ │
│ │ 5. 所以这个文件在簇 3→4→5 │ │
│ │ │ │
│ │ 本质: FAT 表 = 一个单链表, FAT[i] 存的是"下一个簇号" │ │
│ │ 这是最简单的文件分配算法了 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ FAT32 目录项 (32 字节): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Offset 大小 内容 │ │
│ │ 0x00 8B 文件名 (8.3 短文件名) │ │
│ │ 0x08 3B 扩展名 │ │
│ │ 0x0B 1B 属性 (只读/隐藏/系统/卷标/目录/存档) │ │
│ │ 0x0C 1B 保留 │ │
│ │ 0x0D 1B 创建时间 (10ms) │ │
│ │ 0x0E 2B 创建时间 │ │
│ │ 0x10 2B 创建日期 │ │
│ │ 0x12 2B 最后访问日期 │ │
│ │ 0x14 2B 起始簇号高 16 位 │ │
│ │ 0x16 2B 最后修改时间 │ │
│ │ 0x18 2B 最后修改日期 │ │
│ │ 0x1A 2B 起始簇号低 16 位 │ │
│ │ 0x1C 4B 文件大小 (字节) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 4G 限制的来源: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 文件大小字段 = 4 字节 = 32 位 │ │
│ │ 2^32 = 4,294,967,295 字节 ≈ 4GB │ │
│ │ │ │
│ │ 这就是 FAT32 单个文件不能超过 4GB 的原因 │ │
│ │ 不是 FAT 表限制(FAT 表支持到 2TB 分区) │ │
│ │ 是目录项里"文件大小"字段只有 32 位! │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
第2部分:exFAT — FAT32 的现代继任者
┌─────────────────────────────────────────────────────────────┐
│ exFAT — 闪存时代的 FAT 进化版 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 对 FAT32 的改进: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 文件大小: 64 位 → 最大 16EB (理论) │ │
│ │ • 分区大小: 最大 128PB (推荐 512TB) │ │
│ │ • 目录项: 一个文件只用一条记录 │ │
│ │ (FAT32 长文件名用多条记录) │ │
│ │ • 空闲空间管理: 使用 Bitmap (更快) 代替 FAT 表遍历 │ │
│ │ • 时间戳: 精确到 10ms, 支持 UTC 时区 │ │
│ │ • 预分配: 支持, 减少碎片 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 为什么 ESP 不用 exFAT: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 微软直到 2019 年才公开 exFAT 规范, 之前一直收专利费 │ │
│ │ UEFI 规范 (2005年) 只要求固件支持 FAT32 │ │
│ │ → ESP 永远是 FAT32 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 适用: SDXC 卡 (>32GB)、U 盘读写大文件、移动硬盘 │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
第3部分:NTFS — Windows 的脊梁
3.1 NTFS 的核心思想:一切皆文件
┌─────────────────────────────────────────────────────────────┐
│ NTFS 的 MFT — 主文件表 │
├─────────────────────────────────────────────────────────────┤
│ │
│ NTFS 把一切都当作文件,包括元数据本身: │
│ │
│ MFT = Master File Table │
│ 一张巨大的表,每个文件和目录占一条记录 (1KB) │
│ │
│ 前 16 条记录是"元文件" (MFT 自己也是第 0 条): │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ $MFT (0) MFT 自身 — MFT 里的第一条记录 │ │
│ │ $MFTMirr (1) MFT 前 4 条的备份 │ │
│ │ $LogFile (2) Journal 日志 │ │
│ │ $Volume (3) 卷信息 (标签/版本) │ │
│ │ $AttrDef (4) 属性定义表 │ │
│ │ $Root (5) 根目录 │ │
│ │ $Bitmap (6) 簇分配位图 (哪些簇空闲/占用) │ │
│ │ $Boot (7) 引导扇区 │ │
│ │ $BadClus (8) 坏簇列表 │ │
│ │ $Secure (9) 安全描述符 │ │
│ │ $UpCase (10) 大写字母映射表 │ │
│ │ $Extend (11) 扩展元数据目录 │ │
│ │ ... │ │
│ │ 从 16 号开始: 用户的文件和目录 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 单个 MFT 记录的结构 (1KB): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 头部: │ │
│ │ 签名 "FILE", 序列号, 硬链接计数, 属性列表偏移 │ │
│ │ │ │
│ │ 属性列表: (NTFS 的"属性"≈ext4 的"字段") │ │
│ │ $STANDARD_INFORMATION 创建/修改/访问时间+属性标志 │ │
│ │ $FILE_NAME 文件名 (可以有多个: 8.3+长) │ │
│ │ $DATA 文件数据 (小文件就内嵌在MFT里)│ │
│ │ $INDEX_ROOT 目录的 B+ 树根 (如果是目录) │ │
│ │ $SECURITY_DESCRIPTOR ACL权限 (或指向$Secure) │ │
│ │ ... │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 小文件优化: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 如果文件数据很小 (<~700B) → 直接内嵌在 MFT 记录里 │ │
│ │ 这个叫 Resident Attribute │ │
│ │ │ │
│ │ 如果文件数据大 → MFT 记录里存的是数据块的地址 │ │
│ │ 这个叫 Non-Resident Attribute │ │
│ │ │ │
│ │ 很多小于 1KB 的配置文件根本不会占用额外的数据块 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
3.2 NTFS 独有的特性
┌─────────────────────────────────────────────────────────────┐
│ NTFS 的独特能力 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. ADS (Alternate Data Streams) — 备用数据流 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 一个文件可以有多个 $DATA 属性 │ │
│ │ 主数据流: file.txt 的正文 │ │
│ │ 备用数据流: file.txt:zone.identifier │ │
│ │ │ │
│ │ Windows 用这个标记"这个文件是从网上下载的" │ │
│ │ 也可以隐藏恶意数据 (dir /r 才能看到) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 2. 硬链接和符号链接 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ NTFS 支持硬链接 (CreateHardLink) │ │
│ │ NTFS 支持符号链接 (从 Vista 开始) │ │
│ │ 还支持 Junction (目录级符号链接, 只能连目录) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 3. 透明压缩 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 文件/目录级别压缩 (LZNT1 或 XPRESS 算法) │ │
│ │ 对应用透明: 读时自动解压, 写时自动压缩 │ │
│ │ 蓝色文件名 = 已压缩 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 4. ACL 权限 (比 Linux UGO 粒度细得多) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 每个文件可以有自己的访问控制列表 │ │
│ │ 可以精确到: 哪个用户/组的哪种操作 (读/写/执行/删/...) │ │
│ │ 继承: 子文件夹默认继承父级权限 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
第4部分:ext4 — Linux 的默认答案
4.1 ext4 的改进:从间接块到 Extent Tree
┌─────────────────────────────────────────────────────────────┐
│ ext2/3 的间接块 vs ext4 的 extent │
├─────────────────────────────────────────────────────────────┤
│ │
│ ext2/3 的间接块方案 (已经在 [[04-filesystem-concepts]] 介绍了):│
│ │
│ 12 直接指针 + 1 间接 + 1 二级 + 1 三级 │
│ │
│ 问题: 大文件性能差 │
│ │
│ 一个 1GB 的文件: │
│ 块大小 4K → 需要 262,144 个数据块 │
│ 三级间接块 → 需要 16,384 个间接块来存指针 │
│ 每次随机访问都要遍历多级指针 → 开销大 │
│ 追加写入需要不断分配新间接块 → 碎片化 │
│ │
│ ext4 的 Extent Tree: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 不存单个块地址,存"区间" (extent): │ │
│ │ │ │
│ │ inode │ │
│ │ └→ extent_root │ │
│ │ └→ extent: [起始块 1000, 长度 256 块] │ │
│ │ └→ extent: [起始块 1500, 长度 128 块] │ │
│ │ └→ extent: [起始块 2000, 长度 512 块] │ │
│ │ │ │
│ │ 3 条 extent → 描述了 896 个连续数据块 → 覆盖 ~3.5MB │ │
│ │ 连续文件可能只需要 1 条 extent! │ │
│ │ │ │
│ │ 1GB 连续文件 → 只需一棵 4 层的 extent tree │ │
│ │ ext2/3 → 需要 51,200+ 个间接块 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ extent tree 的本质: 用 B-tree 存"连续区间" │
│ 一个 extent 节点 = 1 段连续地址 → 比指针密度高几十倍 │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
4.2 延迟分配 (Delayed Allocation)
┌─────────────────────────────────────────────────────────────┐
│ 延迟分配 — ext4 的性能秘诀 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 传统做法: │
│ write(fd, buf, 4KB) │
│ → 立即分配磁盘块 → 写数据 → 返回 │
│ │
│ 延迟分配: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ write(fd, buf_1, 4KB) │ │
│ │ → 数据先放在内存 Page Cache 里 │ │
│ │ → 不分配磁盘块! │ │
│ │ │ │
│ │ write(fd, buf_2, 4KB) │ │
│ │ → 继续积累在 Page Cache │ │
│ │ │ │
│ │ write(fd, buf_3, 4KB) │ │
│ │ → 继续积累... │ │
│ │ │ │
│ │ ... 过了一段时间 (默认 30s) ... │ │
│ │ 内核 flush 脏页: │ │
│ │ 看到 3 个连续的写请求 → 一次性分配 12KB 连续空间 │ │
│ │ → 减少碎片, 减少元数据操作 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 好处: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 合并多个小写为一次大块分配 → 减少碎片 │ │
│ │ 2. 临时文件可能永远不会分配到磁盘 → 节省 IO │ │
│ │ 3. 写时复制 (COW) 不存在, 但效果类似 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 风险: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 断电时: 数据还在 Page Cache → 丢失 │ │
│ │ 所以 ext4 默认用 data=ordered mode: │ │
│ │ 数据先于元数据落盘 → 不会出现"文件存在但内容为空" │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
第5部分:btrfs — 下一代 Linux 文件系统
┌─────────────────────────────────────────────────────────────┐
│ btrfs 的核心特性速览 │
├─────────────────────────────────────────────────────────────┤
│ │
│ COW (写时复制) — 一切修改都写到新位置 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 见 [[04-filesystem-concepts#第5部分:COW]] │ │
│ │ 核心: 修改数据块 → 复制到新块 → 更新 B-tree → 提交 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Subvolume — btrfs 的"分区" │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 传统分区: │ │
│ │ /dev/sda3 (100GB) /dev/sda4 (300GB) │ │
│ │ 固定大小, 无法动态调整 │ │
│ │ │ │
│ │ btrfs subvolume: │ │
│ │ @ (/) @home (/home) │ │
│ │ 共享同一个 btrfs 池的 400GB 空间 │ │
│ │ 不需要预先分配 —— 用多少占多少 │ │
│ │ │ │
│ │ Arch 安装就是这个: @ 和 @home 两个 subvolume │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Snapshot — COW 的快照能力 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ btrfs subvolume snapshot / /@snap-20260617 │ │
│ │ │ │
│ │ 创建快照: 瞬间完成, 几乎不占空间 │ │
│ │ (因为 COW: 只有被修改的块才需要新副本) │ │
│ │ │ │
│ │ "更新崩了" → 回滚到快照 → 一切恢复 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 透明压缩 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ mount -o compress=zstd /dev/... /mountpoint │ │
│ │ │ │
│ │ 应用写: hello.txt → 内核 → 压缩 → 写到磁盘 │ │
│ │ 应用读: 磁盘 → 内核 → 解压 → hello.txt │ │
│ │ 应用完全不知道数据被压缩了 │ │
│ │ │ │
│ │ 算法: zstd (快+高压缩比, 推荐) / lzo (快) / zlib │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 已知缺陷 (2026年): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • RAID5/6 有 write hole 问题 (数据完整性漏洞) │ │
│ │ • 大量快照 → 碎片化 → 性能下降 │ │
│ │ • 不适合 VM 镜像 / 数据库文件 (用 nocow 挂载选项) │ │
│ │ • 社区在积极修复, 但需要了解这些限制 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
第6部分:XFS 和 ZFS — 另外两个选择
6.1 XFS — 大文件之王
┌─────────────────────────────────────────────────────────────┐
│ XFS — 为"又大又多"而生的文件系统 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 核心设计: Allocation Group (AG) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 把磁盘分成多个 AG, 每个 AG 独立管理 │ │
│ │ │ │
│ │ AG 0 AG 1 AG 2 AG 3 ... AG N │ │
│ │ │ │
│ │ 每个 AG 有: 独立的超级块副本、独立的 inode 管理、 │ │
│ │ 独立的空闲空间 B+ 树 │ │
│ │ │ │
│ │ 好处: 多线程并行操作不同 AG → 线性扩展 │ │
│ │ 在 64 核服务器上, 64 个线程同时读写 64 个 AG │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ B+ 树 — XFS 的"万能数据结构": │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 空闲空间 → B+ 树管理 │ │
│ │ inode 定位 → B+ 树管理 │ │
│ │ extent 映射 → B+ 树管理 │ │
│ │ │ │
│ │ 全部用 B+ 树 → 统一的代码路径, 高性能 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 适用场景: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 数 TB 的大文件 (视频制作/科学数据) │ │
│ │ • 高并发 IO 的服务器 │ │
│ │ • RHEL/CentOS 的默认文件系统 │ │
│ │ │ │
│ │ 不适合: 大量小文件 (ext4 可能更好), │ │
│ │ 需要 snapshot (btrfs/ZFS 才有), │ │
│ │ 不能缩容 (XFS 只能扩大不能缩小) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
6.2 ZFS — 完整的存储栈
┌─────────────────────────────────────────────────────────────┐
│ ZFS — 不止是文件系统 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ZFS 同时做了文件系统 + 卷管理器 + RAID 的事: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ZFS Pool │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Dataset │ │ Dataset │ │ Dataset │ │ │
│ │ │ / │ │ /home │ │ /data │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ │ 下面是物理磁盘: │ │
│ │ [Mirror: sda + sdb] ← 数据集不知道哪些磁盘 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ZFS 的关键特性: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. 端到端校验和 (Checksum) │ │
│ │ 每个数据块存储时计算 checksum │ │
│ │ 读取时验证 → 检测静默数据损坏 (bit rot) │ │
│ │ EXT4/BTRFS 直到最近才加了这功能 │ │
│ │ │ │
│ │ 2. 内置 RAID-Z (类似 RAID5, 但更好) │ │
│ │ 不需要 mdadm / LVM │ │
│ │ 解决了传统 RAID5 的 write hole 问题 │ │
│ │ │ │
│ │ 3. 快照 + 克隆 + Send/Receive │ │
│ │ zfs send pool/dataset@snap | ssh ... zfs receive │ │
│ │ 增量备份的强大方案 │ │
│ │ │ │
│ │ 4. 自适应替换缓存 (ARC) │ │
│ │ ZFS 不依赖 Linux Page Cache, 有自己的内存缓存 │ │
│ │ (这是 ZFS 吃内存的原因) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ZFS 的问题: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • CDDL 许可证 与 Linux GPL 不兼容 → 不能进内核主线 │ │
│ │ • 吃内存 (建议 1GB+ 基础 + 每 TB 存储 1GB ARC) │ │
│ │ • 比 btrfs 更成熟, 但在 Linux 上不如 FreeBSD 原生 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
第7部分:选型指南
7.1 横向对比
┌────────────────────────────────────────────────────────────────────────┐
│ 文件系统选型对比表 │
├──────────┬──────────┬──────────┬──────────┬──────────┬────────┬───────┤
│ │ FAT32 │ NTFS │ ext4 │ btrfs │ XFS │ ZFS │
├──────────┼──────────┼──────────┼──────────┼──────────┼────────┼───────┤
│ 最大文件 │ 4GB │ 16EB │ 16TB │ 16EB │ 8EB │ 16EB │
│ 最大卷 │ 2TB │ 256TB │ 1EB │ 16EB │ 8EB │ 256ZB │
│ Journal │ ❌ │ ✅ │ ✅ │ ❌(COW) │ ✅ │ ❌(COW)│
│ COW │ ❌ │ ❌ │ ❌ │ ✅ │ ❌ │ ✅ │
│ Snapshot │ ❌ │ ❌(VSS) │ ❌ │ ✅ │ ❌ │ ✅ │
│ 压缩 │ ❌ │ ✅ │ ❌ │ ✅ │ ❌ │ ✅ │
│ 校验和 │ ❌ │ ❌ │ ❌(可选)│ ✅ │ ❌ │ ✅ │
│ 案例限制 │ 4G文件 │ Windows │ 极稳 │ 快照 │ 大IO │ 完整 │
│ 平台 │ All │ Win │ Linux │ Linux │ Linux │ 多平台│
└──────────┴──────────┴──────────┴──────────┴──────────┴────────┴───────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
7.2 场景选型建议
┌────────────────────────────────────────────────────────────────────────┐
│ 场景 → 推荐 → 原因 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Linux 桌面 (/) → btrfs 或 ext4 │
│ 需要快照+回滚 → btrfs (玩 Arch 推荐) │
│ 求稳不想折腾 → ext4 │
│ │
│ Linux /boot → FAT32 (ESP) 或 ext4 │
│ UEFI ESP 必须 FAT32 │
│ 传统 /boot 分区用 ext4 够了 │
│ │
│ Linux /home → btrfs subvolume 或 ext4 │
│ btrfs: 快照保护数据 │
│ ext4: 极稳, 性能最好 │
│ │
│ 数据库服务器 → XFS 或 ext4 (禁用 COW) │
│ MySQL/PostgreSQL: XFS 的分配组并行性能好 │
│ 不要用 btrfs 跑数据库! (碎片化+COW 写放大) │
│ │
│ NAS / 文件服务器 → ZFS 或 btrfs │
│ 多个硬盘做 RAID → ZFS 的 RAID-Z 很成熟 │
│ 检测静默数据损坏 → checksum 是必须的 │
│ │
│ U 盘 / 移动硬盘 → exFAT (大文件) 或 FAT32 (兼容性) │
│ Linux/Windows/Mac 三方兼容选 exFAT │
│ 老旧设备 (相机/游戏机) 选 FAT32 │
│ │
│ Windows C: → NTFS (没得选但够好) │
│ │
│ Windows 数据盘 (和 Linux 共享) → NTFS (Linux ntfs3 驱动已成熟) │
│ │
└────────────────────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
核心总结
总结1:四种设计哲学
FAT32: 极简主义 —— 一个链表 (FAT) 解决一切
NTFS: 一切皆文件 —— 包括元数据, MFT 是最核心的数据结构
ext4: 稳中求进 —— 传统 inode + 现代 extent + 延迟分配
btrfs/ZFS: 完整存储栈 —— COW + B-tree + checksum + 快照2
3
4
总结2:一句话选型
ESP → FAT32 (没得选)
Windows → NTFS (没得选)
Linux 桌面 → btrfs (玩) 或 ext4 (稳)
数据库 → XFS
NAS → ZFS
U 盘 → exFAT2
3
4
5
6
章节测试
测试1:FAT32 的 4GB 限制
FAT32 的单个文件最大 4GB 的技术原因是什么?
测试2:NTFS 的 MFT
NTFS 的 MFT 是什么?为什么说 NTFS"一切皆文件"?
测试3:ext4 extent
ext4 的 extent 比 ext2/3 的间接块有什么优势?
测试4:btrfs subvolume
btrfs 的 subvolume 和传统分区的本质区别是什么?
测试5:数据库为何不用 btrfs
为什么 MySQL/PostgreSQL 官方不建议在 btrfs 上跑数据库?
参考答案
测试1答案
FAT32 目录项中"文件大小"字段只有 4 字节(32 位)。2^32 = 4,294,967,295 字节 ≈ 4GB。这不是 FAT 表的问题(FAT32 支持到 2TB 分区),纯粹是目录项这个字段的位宽限制。
测试2答案
MFT(Master File Table)是 NTFS 的核心数据结构,每个文件和目录占一条 1KB 的记录。NTFS 的"一切皆文件"体现在:连元数据也是 MFT 里的记录——$MFT 自己就是第 0 号记录,$LogFile 是第 2 号,根目录 \ 是第 5 号。这种统一抽象简化了内部实现。
测试3答案
extent 存储的是"连续区间"(起始块号 + 块数),而不是单个块地址。一个 1GB 的连续文件如果用 extent 可能只需 4 层 B-tree(~10-100 个元数据块),而间接块方案需要 51,200+ 个间接块。extent 极大减少了大文件的元数据开销。
测试4答案
传统分区有固定的物理边界——/dev/sda3 从 LBA X 到 LBA Y,大小固定。btrfs subvolume 没有固定边界——多个 subvolume 共享同一个 btrfs 存储池,空间按需分配,不需要预先规划大小。这就像"文件夹"有了分区的独立性,但保留了文件夹的灵活性。
测试5答案
因为 btrfs 的 COW(写时复制)对数据库的随机写入极不友好:数据库频繁修改固定位置的 page → 每次修改导致整个数据块复制 → 碎片化 + 写放大 → 性能直线下降。btrfs 提供了 chattr +C(nocow)来禁用 COW,但这同时也禁用了 checksum 和压缩。XFS 的分配组设计更适合数据库的随机写模式。
相关笔记
- [[04-filesystem-concepts]] - 本章所有概念(inode/journal/COW)的具体实现
- [[09-linux-mount]] - 不同文件系统挂载时的特殊选项
- [[12-ext4-deep-dive]] - ext4 的源码级细节
下一步学习
- [ ] 阅读 06 - Linux 启动全流程
学习状态:🟡 开始学习