跳转到内容

ZFS — 把磁盘当成水池,每滴水都贴标签

是什么

ZFS(Zettabyte File System)是 Sun 公司 2003 年公布的文件系统,把”管硬盘”这件事彻底重做了一遍。日常类比:以前每块硬盘像一个独立水桶,要先选桶再倒水;ZFS 把所有硬盘汇成一个水池,应用直接从池子里舀,不用关心水来自哪个桶。

它同时做了三件以前没人一起做过的事:

  • 池化存储:N 块硬盘合成一个池(zpool),文件系统按需取空间
  • 端到端校验:每个数据块都带 256-bit 校验和,读出来对不上立刻知道
  • 写时复制快照:写新数据永不覆盖旧块,“昨天的状态”自动留下来

这三件事后来成了所有现代文件系统的默认要求

为什么重要

不理解 ZFS,下面这些事都没法解释:

  • 为什么 macOS 现在的 APFS 能秒级”恢复昨天”——抄的 ZFS 快照思路
  • 为什么 Linux 的 Btrfs 长得跟 ZFS 像孪生兄弟——直接抄
  • 为什么云厂家的 EBS / S3 都强调”端到端数据完整性”——ZFS 第一个把校验和放进文件系统
  • 为什么硬盘出现”静默坏块”(数据悄悄变了你还不知道)这个词在 2003 后才被广泛讨论——ZFS 让大家第一次看清这个问题

核心要点

ZFS 的三个核心思路可以拆开讲:

  1. 池化(pooled storage):抛弃”一个分区一个文件系统”。所有磁盘进 zpool,文件系统从池里申请空间,像内存 malloc。类比:以前每个房间一个水桶,搬家要倒桶;现在全屋一根水管,水龙头开了就有。

  2. 写时复制(copy-on-write, COW):永不原地覆盖。改一个块,先写新块,再改父指针指过去,旧块自动成为历史。这让快照零成本——只要不删旧块,就还在。

  3. 端到端校验和:每个块的 256-bit 校验和不存在块自己里面,存在指向它的父块里。读时父块先验子块,错了就从镜像或 RAID-Z 里恢复。关键:校验和位置和数据分离,硬盘连”自己骗自己”都做不到。

附加:RAID-Z 解决了传统 RAID-5 的”写洞”——条带写到一半断电会数据/校验不一致,ZFS 用可变条带宽度 + COW 保证每次写要么全成要么全不成。

Merkle 树式校验:每个父块校验子块,根块(uberblock)校验整个树。这棵校验树本身就是 Bitcoin 后来用的同一思想,但 ZFS 早 5 年用在文件系统里。

实践案例

案例 1:建一个池,开一个文件系统

Terminal window
# 三块盘做成 RAID-Z 池
zpool create tank raidz /dev/sda /dev/sdb /dev/sdc
# 池里开文件系统(不用 mkfs,不用 mount)
zfs create tank/photos
zfs create tank/videos
# 看池子状态
zpool status tank

每个 zfs create 不预分空间,要多少给多少,和 Linux 传统的”先分区再 mkfs”完全反过来。

案例 2:快照真的零成本

Terminal window
zfs snapshot tank/photos@yesterday
# ↑ 瞬间完成,不复制任何数据
# COW 已经保证了旧块还在,快照只是"别 GC 它"
# 改了一通后想回滚
zfs rollback tank/photos@yesterday

为什么瞬间:快照不是复制,是”打个标记说这些块还有人引用”。普通 ext4 / XFS 快照要复制元数据,ZFS 因为 COW 已经天然保留旧版,只要给旧块多加一个引用计数

案例 3:校验和救你于静默坏块

Terminal window
zpool scrub tank
# ↑ 后台读全池,每个块对校验和
# 发现某块在硬盘上被宇宙射线翻了一位 → 自动从冗余副本恢复

传统 ext4 不知道数据是否还对,硬盘说”读到 X”它就信。ZFS 不信硬盘,信父块里那个独立校验和

案例 4:克隆一个文件系统当沙盒

Terminal window
zfs snapshot tank/db@before-migration
zfs clone tank/db@before-migration tank/db-test
# ↑ 克隆是可写快照,立即创建一份"独立的"文件系统
# 实际只占改动部分的空间

数据库迁移测试、容器分层都建立在这个能力上。Docker 早期的 layer 思路本质就是 ZFS clone 的简化版。

踩过的坑

  1. 吃 RAM 凶:去重特性需要把所有块的校验和存内存,1TB 数据约 5GB RAM。家用 NAS 默认要关 dedup。

  2. 扩容受限:传统认知”加块盘就扩容”在 ZFS 不成立——只能给 zpool 加新 vdev(一组盘),不能给现有 RAID-Z 加单盘。家用场景这点很难受,2023 年才有 RAID-Z expansion 补丁合入。

  3. 性能不如专用 FS:纯顺序读写场景 ZFS 比 XFS / ext4 慢 10-30%,因为校验和 + COW 有开销。要极致性能选别的,要数据完整性选 ZFS。

  4. 协议许可坑:ZFS 用 CDDL 协议,和 Linux 内核 GPL 不兼容,至今进不了主线。OpenZFS 项目走外挂模块,每次升级内核都可能编不过。这是 Sun 当年和 Linux 阵营斗气的历史遗产。

适用 vs 不适用场景

适用

  • 数据安全 > 性能的场景(备份服务器、家用 NAS、企业存储)
  • 需要快照 / 克隆 / 增量备份的场景(虚拟机镜像、容器镜像、数据库时间机器)
  • 多盘冗余存储(RAID-Z 替代 RAID-5/6)
  • macOS(APFS 已默认;不是 ZFS 但思路一致)

不适用

  • 极致顺序吞吐场景(视频流服务器选 XFS)
  • 内存吃紧的小机器(ZFS 默认 ARC 缓存吃 RAM)
  • 需要在 Linux 主线内核里直接用(CDDL 许可阻挡,需装 OpenZFS 外挂)
  • 需要灵活扩容单盘(直到最近才支持)

历史小故事(可跳过)

  • 2001 年:Sun 工程师 Jeff Bonwick 启动 ZFS 项目,目标是”管理 zettabyte 量级数据”(当时硬盘还按 GB 算,这名字像科幻)
  • 2003 年:Sun 发布白皮书,命名 ZFS。当时业界主流还是 ext3 / NTFS / UFS,没人把”校验和 + 快照 + 池化”放一起
  • 2005 年:作为 OpenSolaris 一部分开源
  • 2007 年:Linux 阵营开始抄,Chris Mason 启动 Btrfs(设计明显参考 ZFS)
  • 2010 年:Oracle 收购 Sun,ZFS 闭源分支 vs OpenZFS 社区分裂
  • 2017 年:Apple 发布 APFS,COW + 快照思想直接来自 ZFS
  • 2023 年:OpenZFS 合入 RAID-Z expansion,补上 20 年的遗憾

学到什么

  1. 不信任硬件——这是 ZFS 最颠覆的世界观。以前 FS 假设硬盘读啥给啥,ZFS 假设硬盘随时撒谎,每块都自己验
  2. 池化 + 按需分配 是把”管理容量”这件事从用户手里收回到系统的关键一步。后来云存储的”无限扩容”幻觉就建在这思路上
  3. 写时复制 = 快照零成本——这个等式被 ZFS 证明后,所有现代 FS / 数据库 / 区块链都在用
  4. 协议 + 时机 决定技术普及。ZFS 技术领先 10 年,但 CDDL 把它挡在 Linux 外,让 Btrfs / APFS 摘了桃子

延伸阅读

关联

  • lfs-1991 —— LFS 1991 年提出”永不原地写”,ZFS 的 COW 直接继承
  • gfs —— GFS 用副本 + 校验和搞分布式数据完整性,ZFS 在单机做同一件事
  • hdfs-2010 —— HDFS 也用块校验思路,但放在应用层;ZFS 放在文件系统层
  • unix-1974 —— Unix 文件系统的 inode 模型是 ZFS 要超越的传统对象

反向链接

  • btrfs-2013 —— Btrfs — Linux 上”写时复制 B-tree”的工业级文件系统
  • gfs —— GFS — 编译器决定不做哪些事
  • hdfs-2010 —— HDFS — 把 GFS 用 Java 重写一遍并撑到 25 PB
  • lfs-1991 —— LFS 1991 — 把整个磁盘当日志写