强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Bcachefs 完全指南 / 第 3 章:架构与设计原理

第 3 章:架构与设计原理

理解底层设计,才能善用高层特性


3.1 整体架构概览

Bcachefs 的架构可以用一句话概括:一个基于 B-Tree of B-Trees 的 CoW 文件系统

┌─────────────────────────────────────────────────────────┐
│                    用户空间 (User Space)                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────────┐  │
│  │ 应用程序  │  │ bcachefs  │  │  mount / bcachefs    │  │
│  │          │  │ -tools   │  │  format / bcachefs    │  │
│  └──────────┘  └──────────┘  │  fsck                 │  │
│                               └──────────────────────┘  │
├─────────────────────────────────────────────────────────┤
│                    内核空间 (Kernel Space)                │
│  ┌─────────────────────────────────────────────────┐    │
│  │              VFS (虚拟文件系统)                    │    │
│  └───────────────────────┬─────────────────────────┘    │
│                          │                               │
│  ┌───────────────────────┴─────────────────────────┐    │
│  │              Bcachefs 文件系统驱动                 │    │
│  │  ┌─────────┐ ┌─────────┐ ┌──────────────────┐   │    │
│  │  │ B-Tree  │ │  CoW    │ │   Journal 系统    │   │    │
│  │  │ 引擎    │ │  引擎   │ │                  │   │    │
│  │  └─────────┘ └─────────┘ └──────────────────┘   │    │
│  │  ┌─────────┐ ┌─────────┐ ┌──────────────────┐   │    │
│  │  │ 压缩    │ │ 校验和  │ │   快照/子卷       │   │    │
│  │  └─────────┘ └─────────┘ └──────────────────┘   │    │
│  │  ┌─────────┐ ┌─────────┐ ┌──────────────────┐   │    │
│  │  │ 去重    │ │ 加密    │ │   多设备/RAID     │   │    │
│  │  └─────────┘ └─────────┘ └──────────────────┘   │    │
│  └───────────────────────┬─────────────────────────┘    │
│                          │                               │
│  ┌───────────────────────┴─────────────────────────┐    │
│  │              Block Layer (块设备层)               │    │
│  └───────────────────────┬─────────────────────────┘    │
│                          │                               │
│  ┌───────────────────────┴─────────────────────────┐    │
│  │          存储设备 (SSD / HDD / NVMe)              │    │
│  └─────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘

3.2 B-Tree 结构

3.2.1 什么是 B-Tree

B-Tree(平衡多路搜索树)是数据库和文件系统中使用最广泛的索引结构。Bcachefs 使用的是 B+Tree 的变体

传统 B-Tree:
          [30 | 60]
         /    |    \
    [10|20] [40|50] [70|80]
     / | \   / | \   / | \
    叶子节点 叶子节点 叶子节点

Bcachefs B-Tree:
  每个节点存储 key-value 对
  key = (inode, offset, size) 三元组
  value = 数据指针 / 元数据

3.2.2 Bcachefs 的 B-Tree 设计

Bcachefs 使用 “B-Tree of B-Trees” 分层结构:

┌─────────────────────────────────────────────────┐
│              Superblock (超级块)                  │
│  存储文件系统元信息、设备列表、配置               │
└──────────────────────┬──────────────────────────┘
                       │
        ┌──────────────┼──────────────┐
        │              │              │
┌───────┴───────┐ ┌────┴─────┐ ┌─────┴─────┐
│  Inodes B-Tree │ │ Extents  │ │ Dirents   │
│  (索引节点)    │ │ B-Tree   │ │ B-Tree    │
│               │ │ (数据)   │ │ (目录)    │
└───────────────┘ └──────────┘ └───────────┘
        │              │              │
┌───────┴───────┐ ┌────┴─────┐ ┌─────┴─────┐
│ 其他 B-Tree   │ │ 校验和   │ │ 扩展属性  │
│ - Snapshots   │ │ B-Tree   │ │ B-Tree    │
│ - Subvolumes  │ │          │ │           │
│ - Xattrs      │ │          │ │           │
└───────────────┘ └──────────┘ └───────────┘

3.2.3 Key-Value 编码

Bcachefs 的 B-Tree 节点存储统一格式的 key-value 对:

Key 格式:
┌──────────┬──────────┬──────────┬──────────┐
│ inode    │ offset   │ size     │ type     │
│ (64 bit) │ (64 bit) │ (32 bit) │ (8 bit)  │
└──────────┴──────────┴──────────┴──────────┘

Key 类型:
  - BKEY_TYPE_INODES     → inode 元数据
  - BKEY_TYPE_EXTENTS    → 数据块指针
  - BKEY_TYPE_DIRENTS    → 目录项
  - BKEY_TYPE_XATTRS     → 扩展属性
  - BKEY_TYPE_ALLOC      → 分配信息
  - BKEY_TYPE_SNAPSHOT   → 快照信息
  - BKEY_TYPE_SUBVOLUME  → 子卷信息

3.2.4 B-Tree 操作复杂度

操作时间复杂度说明
查找O(log N)B-Tree 高度很低,通常 3-4 层
插入O(log N)可能触发节点分裂
删除O(log N)可能触发节点合并
范围扫描O(log N + K)顺序遍历叶子节点

3.3 Copy-on-Write (CoW) 机制

3.3.1 CoW 基本原理

传统文件系统写入:
  1. 读取旧数据块 A
  2. 修改 A 的内容
  3. 写回 A(原地覆盖)
  4. 如果步骤 3 失败 → 数据损坏

Bcachefs CoW 写入:
  1. 分配新数据块 A'
  2. 将新数据写入 A'
  3. 原子更新 B-Tree 指针: A → A'
  4. 如果步骤 3 失败 → A 仍然完整,A' 被回收

3.3.2 CoW 写入流程

写入文件 "data.txt" 的数据:

步骤 1: 读取 B-Tree,找到数据块位置
  ┌──────────────────────────────────┐
  │ Inode: 1234, Offset: 0, → Block A │
  └──────────────────────────────────┘

步骤 2: 分配新块 A',写入新数据
  ┌──────────────────────────────────┐
  │ 新分配: Block A' (写入新数据)     │
  └──────────────────────────────────┘

步骤 3: 创建新的 B-Tree 节点
  ┌──────────────────────────────────┐
  │ Inode: 1234, Offset: 0, → Block A'│
  └──────────────────────────────────┘

步骤 4: 原子更新父节点指针
  旧: parent → [A, B, C]
  新: parent → [A', B, C]   ← 原子操作

步骤 5: 旧块 A 标记为可回收

3.3.3 CoW 的优势与代价

方面优势代价
数据安全崩溃后一致,无需 fsck-
快照O(1) 创建,共享旧数据删除快照时需要遍历
并发读不阻塞写写-写需要锁协调
SSD 友好顺序写入写放大 (Write Amplification)
碎片化-长期使用可能碎片化

3.3.4 写放大问题

写放大 (Write Amplification):

ext4 修改 4KB:
  写入 4KB → 磁盘写入 4KB
  放大比: 1x

bcachefs 修改 4KB (CoW):
  写入新 4KB 数据块 + 更新 B-Tree 节点 + 更新 Journal
  实际磁盘写入: ~12-16KB
  放大比: 3-4x

缓解措施:
  1. 延迟写回 (Write-back) — 合并小写入
  2. 批量提交 B-Tree 节点
  3. 日志压缩
  4. SSD 的 TRIM/UNMAP 支持

3.4 Journal (日志) 系统

3.4.1 日志的作用

无 Journal 的文件系统:
  写入步骤 → 如果在步骤 2/3 之间崩溃
  → 元数据不一致 → 需要 fsck 扫描全盘

有 Journal 的文件系统:
  1. 先写 Journal(日志)
  2. 再写实际数据
  3. 标记 Journal 完成
  如果在步骤 1/2 之间崩溃 → 回放 Journal 恢复

3.4.2 Bcachefs 的 Journal 设计

Journal 结构:
┌─────────────────────────────────────────────────┐
│ Journal Sequence Number (递增序列号)              │
├─────────────────────────────────────────────────┤
│ Entry 1: B-Tree 操作日志                         │
│ Entry 2: 分配器变更                              │
│ Entry 3: 引用计数变更                            │
│ ...                                             │
├─────────────────────────────────────────────────┤
│ Journal 校验和 (保证日志本身完整性)                │
└─────────────────────────────────────────────────┘

Journal 设备:
  - 可以使用专用的快速设备(如 NVMe)存储日志
  - 默认使用主设备
  - 专用日志设备可以减少写放大

3.4.3 Journal 回放

# 崩溃后的恢复流程:
# 1. 挂载时自动检查 Journal
# 2. 查找最近的完整 Journal 条目
# 3. 回放未完成的操作
# 4. 文件系统恢复到一致性状态

# 手动检查 Journal 状态
sudo bcachefs show-super /dev/sdX
# 查看 journal_seq 字段

3.5 存储分配器

3.5.1 Bucket 分配模型

Bcachefs 使用 Bucket(桶) 作为基本分配单元:

设备分区:
┌─────────┬─────────┬─────────┬─────────┬─────────┐
│ Bucket 0│ Bucket 1│ Bucket 2│ Bucket 3│ ...     │
│ 512 KB  │ 512 KB  │ 512 KB  │ 512 KB  │         │
└─────────┴─────────┴─────────┴─────────┴─────────┘

每个 Bucket 的状态:
  - FREE (空闲)
  - DIRTY (有脏数据)
  - CLEAN (有干净数据,可回收)
  - META (存储元数据)
  - NEEDS_GC (需要垃圾回收)

3.5.2 Bucket 大小选择

# 创建文件系统时指定 bucket 大小
sudo bcachefs format /dev/sdX --bucket_size=256K

# Bucket 大小的选择建议:
# 小 bucket (64K-256K):
#   - 适合小文件多的场景
#   - 减少空间浪费
#   - 元数据开销更大
#
# 大 bucket (512K-2M):
#   - 适合大文件场景
#   - 元数据开销小
#   - 可能浪费空间(小文件不满一个 bucket)

# 默认 bucket 大小根据设备大小自动选择:
# 设备 < 50GB  → 64KB
# 设备 < 500GB → 128KB
# 设备 < 5TB   → 256KB
# 设备 < 50TB  → 512KB
# 设备 ≥ 50TB  → 1MB

3.5.3 垃圾回收 (Garbage Collection)

CoW 系统的 GC 问题:

1. 文件 "A" 占用 Bucket 1 (Blocks 0-9)
2. 文件 "A" 被修改 → CoW 写入 Bucket 2
3. Bucket 1 中的部分 Block 不再被引用
4. Bucket 1 变成"部分垃圾"
5. 需要 GC 来回收空间

GC 流程:
  ┌──────────────────────────────────┐
  │ 1. 扫描 B-Tree,标记存活数据块    │
  │ 2. 扫描 Bucket,识别垃圾数据      │
  │ 3. 将存活数据复制到新 Bucket       │
  │ 4. 释放旧 Bucket                  │
  └──────────────────────────────────┘

GC 的开销:
  - CPU: 扫描和复制数据
  - I/O: 读取旧数据,写入新数据
  - 时间: 大文件系统可能需要数分钟到数小时

3.6 多设备架构

3.6.1 设备角色

Bcachefs 支持将不同类型的设备分配不同角色:

角色类型:
  - foreground (前台): 主要数据存储
  - background (后台): 大容量存储(如 HDD)
  - journal (日志): 专用日志设备
  - promote (提升): 热数据缓存(如 NVMe)

分层存储架构:
┌───────────────────────────────────────────┐
│            应用程序层                       │
├───────────────────────────────────────────┤
│        Bcachefs 文件系统                    │
│  ┌─────────┐                               │
│  │ Promote │ ← NVMe SSD (热数据缓存)       │
│  └────┬────┘                               │
│       ↓ 热数据提升                          │
│  ┌─────────┐                               │
│  │Foreground│ ← SSD (主存储)                │
│  └────┬────┘                               │
│       ↓ 冷数据降级                          │
│  ┌─────────┐                               │
│  │Background│ ← HDD (大容量)                │
│  └─────────┘                               │
└───────────────────────────────────────────┘

3.6.2 数据放置策略

# 指定设备角色
sudo bcachefs format \
    --foreground_target=ssd \
    --background_target=hdd \
    --promote_target=nvme \
    --label=ssd /dev/sda \
    --label=hdd /dev/sdb \
    --label=nvme /dev/nvme0n1

3.6.3 多设备元数据管理

多设备 B-Tree:
  ┌────────────────────────────────────────────┐
  │              B-Tree 节点                     │
  │  ┌──────────────────────────────────────┐   │
  │  │ Key: Inode 1234, Offset 0            │   │
  │  │ Ptr 0: dev=0 (ssd), bucket=100       │   │
  │  │ Ptr 1: dev=1 (hdd), bucket=500       │   │
  │  └──────────────────────────────────────┘   │
  │  ┌──────────────────────────────────────┐   │
  │  │ Key: Inode 1234, Offset 64K          │   │
  │  │ Ptr 0: dev=0 (ssd), bucket=101       │   │
  │  │ Ptr 1: dev=1 (hdd), bucket=501       │   │
  │  └──────────────────────────────────────┘   │
  └────────────────────────────────────────────┘
  
  每个数据块可以有多个副本存储在不同设备上

3.7 校验和与完整性保护

3.7.1 校验和层次

Bcachefs 完整性保护层次:

1. 数据校验和 (Data Checksum):
   ┌──────────────────────────────────┐
   │ 数据块: "Hello World"            │
   │ 校验和: crc32c("Hello World")    │
   │ 存储在 B-Tree 节点的 value 中    │
   └──────────────────────────────────┘

2. 元数据校验和 (Metadata Checksum):
   ┌──────────────────────────────────┐
   │ B-Tree 节点数据                   │
   │ 校验和: sha256(节点数据)          │
   └──────────────────────────────────┘

3. Journal 校验和:
   ┌──────────────────────────────────┐
   │ Journal 条目数据                  │
   │ 校验和: (Journal 条目)            │
   └──────────────────────────────────┘

3.7.2 校验和算法对比

算法速度碰撞概率适用场景
crc32c~15 GB/s2^-32默认,适合大多数场景
crc64~10 GB/s2^-64需要更强校验
xxhash~25 GB/s2^-64性能优先
sha256~0.5 GB/s2^-128安全要求极高
# 创建文件系统时指定校验和算法
sudo bcachefs format /dev/sdX --checksum=xxhash

# 查看当前校验和算法
sudo bcachefs show-super /dev/sdX | grep checksum

3.8 压缩实现

3.8.1 压缩流程

写入路径:
  ┌─────────┐     ┌──────────┐     ┌──────────┐
  │ 用户数据 │ ──→ │ 压缩引擎 │ ──→ │ 校验和   │ ──→ 写入磁盘
  │ 4KB     │     │ zstd     │     │ 压缩后   │
  └─────────┘     └──────────┘     └──────────┘
                   输出: 1.5KB      计算: crc32c

读取路径:
  ┌──────────┐     ┌──────────┐     ┌─────────┐
  │ 读取磁盘 │ ──→ │ 校验和   │ ──→ │ 解压缩  │ ──→ 用户数据
  │ 压缩数据 │     │ 验证     │     │ zstd    │     4KB
  └──────────┘     └──────────┘     └─────────┘

3.8.2 压缩与 CoW 的交互

注意: Bcachefs 的压缩是在 extent 级别进行的

1. 小文件 (< bucket_size):
   整个文件压缩后存入一个 bucket
   → 压缩效果最好

2. 大文件:
   按 extent 分块压缩
   → 每个 extent 独立压缩

3. 不可压缩数据:
   检测到压缩比 < 1.1 时跳过
   → 避免浪费 CPU

3.9 与其他文件系统架构对比

设计理念对比

维度ext4BtrfsZFSBcachefs
元数据结构表 (table-based)B-TreeB+TreeB-Tree of B-Trees
数据管理ExtentExtentBlockBucket + Extent
CoW
日志独立 JournalCOW Log TreeZIL/SLOGJournal
校验和
分配单元Block GroupChunkvdevBucket

内核位置对比

Linux 内核文件系统层次:

VFS (Virtual File System)
├── ext4        ← 内核模块, 非常成熟
├── XFS         ← 内核模块, 非常成熟
├── Btrfs       ← 内核模块, 15年+ 历史
├── bcachefs    ← 内核模块, 主线 2024 年加入
│
└── (非主线)
    ├── ZFS      ← 需要 DKMS/OpenZFS 模块
    └── NTFS-3G  ← FUSE 用户空间实现

3.10 关键数据结构

3.10.1 Superblock (超级块)

Superblock 存储在设备的固定位置,包含:

┌──────────────────────────────────────────────┐
│ Magic Number: 0xca23f8b6bcacfe48             │
│ Version: (major, minor)                      │
│ UUID: 文件系统唯一标识                        │
│ Block Size: 通常 4KB                         │
│ Bucket Size: 分配单元大小                     │
│ Devices[]: 设备列表及角色                     │
│ Journal Location: 日志位置                    │
│ Root B-Tree: 根 B-Tree 指针                  │
│ Creation Time: 创建时间                       │
│ Checksum: 超级块自身的校验和                  │
└──────────────────────────────────────────────┘
# 查看超级块信息
sudo bcachefs show-super /dev/sdX

3.10.2 Inode 结构

Inode (索引节点) 存储文件元信息:

┌──────────────────────────────────────────────┐
│ Mode: 文件类型和权限                           │
│ UID/GID: 所有者信息                           │
│ Size: 文件大小                                │
│ Atime/Mtime/Ctime: 时间戳                     │
│ Nlink: 硬链接计数                             │
│ Flags: 文件标志(压缩、加密等)                 │
│ Hash Seed: 目录哈希种子                        │
└──────────────────────────────────────────────┘

3.11 本章小结

概念要点
B-TreeBcachefs 使用 B-Tree of B-Trees 存储所有元数据
CoW写时复制保证崩溃一致性,但有写放大
Journal前写日志进一步保障一致性
Bucket基本分配单元,大小影响空间效率和元数据开销
校验和数据 + 元数据 + Journal 三层保护
多设备支持 SSD/HDD 分层、数据迁移

理解这些概念后的操作意义

  1. Bucket 大小 → 影响小文件的空间效率
  2. CoW 写放大 → 影响 HDD 的随机写性能
  3. Journal 设备 → 可用 NVMe 加速元数据操作
  4. 校验和选择 → 权衡安全性与性能
  5. GC 策略 → 影响长期使用的性能稳定性

扩展阅读


上一章: ← 第 2 章:安装 | 下一章: 第 4 章:基础操作 →