Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 系统与高性能 / Systems & Performance

操作系统 / Operating Systems

1. OS 底层知识学习路线 / A Learning Path for Operating System Internals

2. 存储硬件基础 — 磁盘到底怎么存数据 / Storage Hardware Fundamentals: How Disks Store Data

3. BIOS vs UEFI — 固件的本质 / BIOS and UEFI: Understanding Firmware

4. 磁盘分区表 — GPT 与 MBR / Disk Partition Tables: GPT and MBR

5. 文件系统核心概念 — inode、journal、COW / Filesystem Concepts: Inodes, Journaling, and Copy-on-Write

6. 常见文件系统格式详解 — FAT 到 ZFS 的进化史 / Filesystem Formats from FAT to ZFS

7. Linux 启动全流程 — 从通电到登录提示符 / The Linux Boot Process from Power-On to Login

8. Windows 启动全流程 — 与 Linux 的对比视角 / The Windows Boot Process in Comparison with Linux

9. Linux 文件系统层次结构 (FHS) — 目录树的哲学 / The Linux Filesystem Hierarchy Standard

10. Linux 挂载机制 — mount、VFS 与 fstab / Linux Mounting with Mount, VFS, and Fstab

11. Linux 磁盘管理实战 — 从分区到挂载全流程 / Practical Linux Disk Management from Partitioning to Mounting

12. Windows 磁盘与文件系统 — 盘符帝国的秩序 / Windows Disks and Filesystems

13. ext4 深入 — 从超级块到 Extent Tree / Ext4 in Depth from Superblocks to Extent Trees

14. btrfs 深入 — B-tree 是万能的 / Btrfs in Depth and Its B-Tree Architecture

15. 双系统 — EFI 分区共存与 GRUB chainload / Dual Boot with Shared EFI Partitions and GRUB Chainloading

本页目录

常见文件系统格式详解 — 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 内核  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
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 位!                 │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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
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 盘读写大文件、移动硬盘             │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第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 的配置文件根本不会占用额外的数据块        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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
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 粒度细得多)                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 每个文件可以有自己的访问控制列表                       │   │
│  │ 可以精确到: 哪个用户/组的哪种操作 (读/写/执行/删/...)  │   │
│  │ 继承: 子文件夹默认继承父级权限                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第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 段连续地址 → 比指针密度高几十倍        │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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:                 │   │
│  │ 数据先于元数据落盘 → 不会出现"文件存在但内容为空"     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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
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 挂载选项)     │   │
│  │ • 社区在积极修复, 但需要了解这些限制                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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
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 只能扩大不能缩小)               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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
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 原生   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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
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  │ 多平台│
└──────────┴──────────┴──────────┴──────────┴──────────┴────────┴───────┘
1
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 驱动已成熟)       │
│                                                                        │
└────────────────────────────────────────────────────────────────────────┘
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

核心总结 ​

总结1:四种设计哲学 ​

FAT32:  极简主义 —— 一个链表 (FAT) 解决一切
NTFS:   一切皆文件 —— 包括元数据, MFT 是最核心的数据结构
ext4:   稳中求进 —— 传统 inode + 现代 extent + 延迟分配
btrfs/ZFS: 完整存储栈 —— COW + B-tree + checksum + 快照
1
2
3
4

总结2:一句话选型 ​

ESP → FAT32 (没得选)
Windows → NTFS (没得选)
Linux 桌面 → btrfs (玩) 或 ext4 (稳)
数据库 → XFS
NAS → ZFS
U 盘 → exFAT
1
2
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 启动全流程

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇5. 文件系统核心概念 — inode、journal、COW / Filesystem Concepts: Inodes, Journaling, and Copy-on-Write
下一篇7. Linux 启动全流程 — 从通电到登录提示符 / The Linux Boot Process from Power-On to Login

持续记录,持续成长

Copyright © Tidenflow