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

本页目录

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

📅 创建时间:2026-06-17 🏷️ 标签:#btrfs #COW #B-tree #subvolume #snapshot #压缩 📚 前置知识:[[04-filesystem-concepts]], [[05-filesystem-formats]], [[12-ext4-deep-dive]]


📋 本章目标 ​

  • 理解 btrfs 的核心理念——B-tree 管理一切
  • 深入 COW 的底层实现——修改一棵叶子引发整条路径复制
  • 掌握 subvolume——不需要预先规划大小的"分区"
  • 掌握 snapshot——基于 COW 的瞬间快照
  • 理解透明压缩——zstd 在 btrfs 中的实际效果
  • 了解内置 RAID 和 Send/Receive
  • 认识 btrfs 的已知缺陷和避坑指南

第1部分:B-tree 是一切 — btrfs 的核心哲学 ​

1.1 btrfs 和 ext4 的根本区别 ​

┌─────────────────────────────────────────────────────────────┐
│              ext4 的数据结构          btrfs 的数据结构        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ext4: 多种固定位置的结构                   btrfs: 一切皆 B-tree          │
│                                                             │
│  Superblock → 固定位置                   Superblock → 存 B-tree 根地址│
│  GDT        → Superblock 之后            B-tree → 存 inode 定位      │
│  Bitmap     → 每个 Group 里               B-tree → 存 extent 映射     │
│  Inode Table → 每个 Group 里               B-tree → 存空闲空间        │
│  Inode      → Inode Table 里              B-tree → 存目录项           │
│  Extent Tree → Inode 里                    ...                          │
│                                                             │
│  ext4 的缺点:                               btrfs 的优势:              │
│  ┌─────────────────────────────────────┐  ┌─────────────────────┐   │
│  │ 每种数据结构位置固定              │  │ 动态分配, 按需增长  │   │
│  │ inode 数量在格式化时固定          │  │ inode 动态分配      │   │
│  │ 不能缩容                          │  │ 可以缩容            │   │
│  └─────────────────────────────────────┘  └─────────────────────┘   │
│                                                             │
│  B-tree 的一个节点:                                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ header: 层级, 条目数, 类型                          │   │
│  │ key[0]: (objectid, type, offset) → 数据              │   │
│  │ key[1]: (objectid, type, offset) → 数据              │   │
│  │ ...                                                 │   │
│  │                                                     │   │
│  │ 所有东西都是 key-value → 统一的数据结构              │   │
│  │ 代码复用, 一致的操作 → insert/search/delete 都一样   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

1.2 btrfs 的 B-tree 森林 ​

┌─────────────────────────────────────────────────────────────┐
│              btrfs 的主要 B-tree                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  一棵 btrfs 文件系统包含多棵 B-tree:                          │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  ROOT_TREE     存所有其他 B-tree 的根地址             │   │
│  │       │                                              │   │
│  │       ├── FS_TREE (subvolume 0)                    │   │
│  │       │      ├── inode 项                           │   │
│  │       │      ├── extent 数据项                       │   │
│  │       │      └── 目录项                             │   │
│  │       │                                              │   │
│  │       ├── EXTENT_TREE  空闲空间 + 已分配 extent       │   │
│  │       ├── CHUNK_TREE   逻辑地址 → 物理设备映射        │   │
│  │       ├── DEV_TREE     设备信息                       │   │
│  │       ├── CSUM_TREE    数据块校验和                   │   │
│  │       └── DATA_RELOC   在线数据迁移用                 │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  关键: FS_TREE 每个 subvolume 有一棵                        │
│        所以你创建的 @ 和 @home 各有自己独立的 FS_TREE        │
│        它们互不干扰,但共享底层 EXTENT_TREE                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第2部分:COW 的底层实现 — 复制整条路径 ​

2.1 修改一个块的代价 ​

┌─────────────────────────────────────────────────────────────┐
│              COW 修改一个数据块的实际流程                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  你要修改文件的一个数据块 (物理块 P):                        │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  修改前:                                            │   │
│  │    ROOT_TREE                                       │   │
│  │      └→ FS_TREE (subvolume @)                      │   │
│  │           └→ inode item (inode 42)                 │   │
│  │                └→ extent item (逻辑L→物理P)          │   │
│  │                          数据在 P                    │   │
│  │                                                     │   │
│  │  修改流程:                                           │   │
│  │  1. 分配新数据块 P' → 把修改后的数据写进去             │   │
│  │                                                     │   │
│  │  2. 更新 extent item: "逻辑L→物理P" → "逻辑L→物理P'"│   │
│  │     但 extent item 本身在一个 B-tree 叶子节点里       │   │
│  │     修改一个叶子 → COW: 复制这条叶子 (在磁盘上)       │   │
│  │                                                     │   │
│  │  3. 叶子节点被复制 → 它的父节点指针要更新              │   │
│  │     → 复制父节点 → 再往上...                         │   │
│  │                                                     │   │
│  │  4. 一直复制到树根 → 根地址变了 → 更新 ROOT_TREE     │   │
│  │     → 复制 ROOT_TREE 的叶子 → ...                   │   │
│  │                                                     │   │
│  │  5. 最终: 根地址更新 → 一次原子写入 → 提交完成        │   │
│  │                                                     │   │
│  │  小结: 修改 1 个 4KB 数据块 → 可能复制 数十个           │   │
│  │         元数据节点 (每个也是 4KB+)                     │   │
│  │         这就是 COW 的"树路径复制"成本               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  为什么这不算太糟:                                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │ 1. 只复制修改路径上的节点 → 不是整棵树               │   │
│  │ 2. 树的高度通常只有 3-4 层 → 通常是 ~4-10 个节点     │   │
│  │ 3. 相近时间的修改可以批量提交 → 分摊成本             │   │
│  │ 4. 延迟分配类比 → btrfs 也在内存中积累修改再刷盘     │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

2.2 COW 对随机写入的影响 ​

┌─────────────────────────────────────────────────────────────┐
│              为什么数据库在 btrfs 上跑得慢                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  数据库的特点: 频繁修改固定位置的 page (8KB)                  │
│                                                             │
│  btrfs 的困境:                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  数据库修改 1 个 8KB page:                           │   │
│  │  → COW: 8KB 写到新位置 + 复制树路径                  │   │
│  │  → 旧 page 成为 COW 碎片                              │   │
│  │                                                     │   │
│  │  数据库每秒修改几千个 page:                           │   │
│  │  → 几千 × COW 树路径复制                              │   │
│  │  → 文件碎片化 (每次写一个新位置)                      │   │
│  │  → 元数据 B-tree 快速增长                             │   │
│  │  → GC 压力增大                                       │   │
│  │  → 性能崩溃                                         │   │
│  │                                                     │   │
│  │  解决: chattr +C /mnt/db  ← 此目录禁用 COW           │   │
│  │        但代价: 失去 checksum, 压缩, snapshot           │   │
│  │        (对此目录而言)                                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  哪些场景禁用 COW:                                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  ❌ 数据库文件 (MySQL/PostgreSQL/SQLite)              │   │
│  │  ❌ 虚拟机镜像 (.qcow2/.vdi/.vmdk)                   │   │
│  │  ❌ BitTorrent 下载目录 (随机写)                      │   │
│  │  ❌ swap 文件 (如果有的话)                            │   │
│  │                                                     │   │
│  │  ✅ 普通文件、源代码、文档 → COW 完全 OK              │   │
│  │  ✅ 媒体文件 (写一次读多次)                          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第3部分:Subvolume 与 Snapshot — btrfs 的杀手功能 ​

3.1 Subvolume — 灵活的"分区" ​

┌─────────────────────────────────────────────────────────────┐
│              Subvolume 与传统分区                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  传统分区:                                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 100GB 磁盘                                          │   │
│  │ sda1: 40GB (/)         ← 固定边界                    │   │
│  │ sda2: 60GB (/home)     ← 固定边界                    │   │
│  │                                                     │   │
│  │ / 满了, /home 还有 30GB → 无法调整! 需要 resize2fs   │   │
│  │ 而且 resize 不是所有文件系统都支持                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  btrfs subvolume:                                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 100GB btrfs 分区                                     │   │
│  │ @ (/)          ← subvolume, 当前用了 35GB             │   │
│  │ @home (/home)  ← subvolume, 当前用了 20GB            │   │
│  │                                                     │   │
│  │ 共享 100GB 池 → @ 和 @home 按需取用                   │   │
│  │ 不需要"调整分区大小" → subvolume 没有固定大小!        │   │
│  │                                                     │   │
│  │ $ btrfs subvolume create /mnt/@vms                   │   │
│  │ $ btrfs subvolume list /                             │   │
│  │ ID 256 gen 12345 top level 5 path @                  │   │
│  │ ID 257 gen 12346 top level 5 path @home               │   │
│  │ ID 258 gen 12347 top level 5 path @vms               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Subvolume 的操作:                                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ btrfs subvolume create <path>    创建子卷             │   │
│  │ btrfs subvolume delete <path>    删除子卷             │   │
│  │ btrfs subvolume list <path>      列出子卷             │   │
│  │ btrfs subvolume show <path>      显示子卷详情          │   │
│  │ btrfs subvolume set-default <id> 设置默认挂载子卷      │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Subvolume 的"边界"概念:                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Subvolume 之间不可硬链接 — 它们有不同的 inode 编号空间│   │
│  │ Subvolume 看起来像目录 — 但对应用来说是独立挂载点     │   │
│  │ Snapshot 只能对 subvolume 做 — 不能对普通目录做       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

3.2 Snapshot — 时间冻结 ​

┌─────────────────────────────────────────────────────────────┐
│              Snapshot = COW 的副产物                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  创建快照:                                                  │
│  $ btrfs subvolume snapshot / /.snap-20260617               │
│  Create a snapshot of '/' in '/.snap-20260617'              │
│                                                             │
│  这做了什么? 几乎什么都没做。                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  创建 snapshot 时:                                  │   │
│  │  1. 复制 @ (/) 的 FS_TREE 根节点地址                │   │
│  │  2. 在 ROOT_TREE 里新增一条"这里有个 snapshot"       │   │
│  │  3. 给这个 snapshot 一个新的 subvolume ID           │   │
│  │                                                     │   │
│  │  没有复制任何文件数据!                               │   │
│  │  两个 subvolume 共享同样的数据块                     │   │
│  │                                                     │   │
│  │  只有当你修改文件时, COW 才真正"分裂":               │   │
│  │  → 原 subvolume: 数据 → COW → 新位置                │   │
│  │  → snapshot:    数据 → 还在老位置 (不变)             │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  实际应用:                                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  场景 1: 系统更新前建快照                             │   │
│  │  $ btrfs subvolume snapshot / /.snap-before-update  │   │
│  │  $ sudo pacman -Syu           ← 更新失败?            │   │
│  │  $ sudo mount -o subvol=.snap-before-update ...     │   │
│  │  → 还原到快照 → 一切恢复                             │   │
│  │                                                     │   │
│  │  场景 2: 用 snapper 自动管理快照                     │   │
│  │  $ sudo pacman -S snapper                            │   │
│  │  $ sudo snapper -c root create-config /             │   │
│  │  snapper 自动:                                       │   │
│  │    • 每次 pacman 事务前后建快照                       │   │
│  │    • 每小时建一次                                    │   │
│  │    • 每天/每周/每月保留策略                           │   │
│  │    • 老旧快照自动清理                                 │   │
│  │                                                     │   │
│  │  场景 3: Send/Receive — 备份/迁移                    │   │
│  │  $ btrfs send /.snap-20260617 | ssh server \        │   │
│  │    btrfs receive /backup/pool                        │   │
│  │  → 增量传输整个 subvolume 状态到远程机器              │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第4部分:透明压缩 — 对应用不可见的省空间魔法 ​

┌─────────────────────────────────────────────────────────────┐
│              btrfs 透明压缩 — 使用指南                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  mount -o compress=zstd  →  一切写入自动压缩                 │
│                                                             │
│  压缩效果 (实际测试):                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 数据类型         原始大小     zstd压缩后   压缩比     │   │
│  │ ─────────────────────────────────────────────────  │   │
│  │ 源代码 (C/Rust)   1GB         250MB        4:1     │   │
│  │ 文本日志           500MB       80MB         6:1     │   │
│  │ 已压缩文件         1GB         1GB          1:1     │   │
│  │ (视频/jpg/zip)     (zstd 检测到不可压缩 → 跳过)      │   │
│  │ 虚拟机镜像         10GB        8GB          1.25:1  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  三种压缩算法:                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ zlib   → 最高压缩比, 最慢                           │   │
│  │ lzo    → 最快, 压缩比一般 (已不推荐)                  │   │
│  │ zstd   → 速度和压缩比的甜点 ← 推荐!                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  压缩选项:                                                  │
│  compress=zstd          → 自动压缩                         │
│  compress=zstd:3        → zstd 级别 3 (默认)               │
│  compress=zstd:9        → 更高压缩比, 更慢                  │
│  compress-force=zstd    → 即使不可压缩也强制压缩             │
│                          (一般不要用, 白费 CPU)             │
│                                                             │
│  查看压缩效果:                                              │
│  $ sudo compsize /                                         │
│  Type       Perc     Disk Usage   Uncompressed Referenced  │
│  TOTAL       71%      8.5G          12G          11G       │
│  zstd        60%      5.0G         8.3G         7.0G       │
│  none       100%      3.5G         3.5G         3.5G       │
│  ↑ 空间省了 29%                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第5部分:已知缺陷和避坑指南 ​

┌─────────────────────────────────────────────────────────────┐
│              btrfs 避坑指南 (截至 2026)                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. RAID5/6 的 Write Hole                                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ RAID5/6 在断电时可能产生不完整条带 → 静默数据损坏      │   │
│  │ → 不要用 btrfs 的 RAID5/6!用 RAID0/1/10             │   │
│  │ → 如果需要 RAID5/6 → 用 mdadm 底层做, btrfs 上层用    │   │
│  │ → 或用 ZFS (RAID-Z 解决了 write hole)               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  2. 大量快照 → 碎片 → 性能下降                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 症状: 系统用久了变慢                                 │   │
│  │ 原因: 数百个快照 → 大量旧版本数据 → 元数据膨胀        │   │
│  │ 解法:                                               │   │
│  │   • 设置 snapper 的保留策略, 定期清理旧快照           │   │
│  │   • btrfs balance (重新平衡数据分布)                 │   │
│  │   • btrfs subvolume delete 删除不需要的快照          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  3. 高性能随机写 → 禁用 COW                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ chattr +C /path/to/db  (对目录)                     │   │
│  │ chattr +C /path/to/vm.img (对文件, 必须先 touch 再设)│   │
│  │                                                     │   │
│  │ 或用 mount 选项在整个 subvolume 禁用:                │   │
│  │ mount -o nodatacow /dev/xxx /mnt/nocow              │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  4. fsck 不够成熟                                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ btrfs check 可以修复大部分问题                        │   │
│  │ 但极端损坏情况下不如 ext4 的 fsck 可靠               │   │
│  │ → 定期做 btrfs scrub (数据完整性检查)                 │   │
│  │ → 重要数据用 snapshot + send 做远程备份              │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  btrfs 日常维护三板斧:                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │ $ sudo btrfs scrub start /          ← 每月一次      │   │
│  │   检查所有数据的 checksum → 有损坏报警               │   │
│  │                                                     │   │
│  │ $ sudo btrfs balance start /        ← 每季度一次    │   │
│  │   重新平衡数据分布 → 清理碎片                        │   │
│  │   (不需要 full balance, 用 dusage=5 只平衡低利用率块)│   │
│  │                                                     │   │
│  │ $ sudo btrfs filesystem df /        ← 随时可查      │   │
│  │   查看 btrfs 内部空间分配情况                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

核心总结 ​

总结1:btrfs 快速参考卡 ​

核心数据结构: B-tree (所有东西)
更新方式:     COW (写时复制)
杀手功能:     subvolume + snapshot + 透明压缩
已知缺陷:     RAID5/6 write hole, 大量快照导致碎片
维护:        scrub (每月) + balance (每季度)
1
2
3
4
5

总结2:btrfs vs ext4 选型 ​

选 btrfs: 需要 snapshot/快照回滚/透明压缩/灵活 subvolume
选 ext4:  追求极稳/跑数据库/VM/不想学维护命令
1
2

总结3:COW 的正确用法 ​

普通文件 → COW → 完美
数据库/VM → nocow → 必需
snapshot → COW 的馈赠 → 用好它
1
2
3

章节测试 ​

测试1:COW 成本 ​

修改 btrfs 中一个 4KB 数据块。除了这个数据块本身,还需要写入多少块?为什么?

测试2:snapshot 的占用 ​

创建一个 100GB subvolume 的快照。快照会立即占用多少额外磁盘空间?

测试3:nocow ​

chattr +C 对目录的作用是什么?代价是什么?

测试4:scrub vs balance ​

btrfs scrub 和 btrfs balance 各是什么用途?应该多久执行一次?


参考答案 ​

测试1答案 ​

除了数据块本身,还需要写入从该数据块的 extent item 所在的叶子节点一直到树根的所有节点。因为 B-tree 的 COW 要求修改叶子 → 复制叶子 → 修改父节点 → 复制父节点 → ... → 直到根。树高通常 3-4 层,所以通常需要额外写入 4-10 个元数据块(每个 4KB+)。这就是 COW 的写放大成本。

测试2答案 ​

几乎不占。snapshot 创建时只是复制了 subvolume 的 FS_TREE 根指针,没有复制任何数据块。两个 subvolume 共享所有数据块。只有当原始 subvolume 中的文件被修改时,COW 才将修改的数据写入新块,此时新旧版本开始分化,snapshot 才逐渐占据额外的空间。

测试3答案 ​

chattr +C 对该目录及其中的新文件禁用 COW。代价:失去该目录中所有文件的 checksum 保护、透明压缩和 snapshot 的一致性保证。对于数据库和 VM 镜像这是必要的性能优化,但对于一般文件不应该使用。

测试4答案 ​

  • scrub:遍历所有数据块,重新计算 checksum,与存储的 checksum 对比。检测静默数据损坏。建议每月执行。
  • balance:重新分配数据块在磁盘上的分布,回收未充分利用的块组,减少碎片。类似磁盘碎片整理 + 空间回收。建议每季度执行(但不需要 full balance,用过滤器如 dusage=5)。

相关笔记 ​

  • [[04-filesystem-concepts]] - COW 的概念基础
  • [[05-filesystem-formats]] - btrfs 与 ext4/ZFS 的横向对比
  • [[12-ext4-deep-dive]] - 另一种哲学:Journal vs COW
  • [[10-linux-disk-practice]] - btrfs subvolume 的创建和挂载

下一步学习 ​

  • [ ] 阅读 14 - 双系统:EFI 分区共存与 GRUB chainload

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇13. ext4 深入 — 从超级块到 Extent Tree / Ext4 in Depth from Superblocks to Extent Trees
下一篇15. 双系统 — EFI 分区共存与 GRUB chainload / Dual Boot with Shared EFI Partitions and GRUB Chainloading

持续记录,持续成长

Copyright © Tidenflow