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 的三个核心思路可以拆开讲:
-
池化(pooled storage):抛弃”一个分区一个文件系统”。所有磁盘进 zpool,文件系统从池里申请空间,像内存 malloc。类比:以前每个房间一个水桶,搬家要倒桶;现在全屋一根水管,水龙头开了就有。
-
写时复制(copy-on-write, COW):永不原地覆盖。改一个块,先写新块,再改父指针指过去,旧块自动成为历史。这让快照零成本——只要不删旧块,就还在。
-
端到端校验和:每个块的 256-bit 校验和不存在块自己里面,存在指向它的父块里。读时父块先验子块,错了就从镜像或 RAID-Z 里恢复。关键:校验和位置和数据分离,硬盘连”自己骗自己”都做不到。
附加:RAID-Z 解决了传统 RAID-5 的”写洞”——条带写到一半断电会数据/校验不一致,ZFS 用可变条带宽度 + COW 保证每次写要么全成要么全不成。
Merkle 树式校验:每个父块校验子块,根块(uberblock)校验整个树。这棵校验树本身就是 Bitcoin 后来用的同一思想,但 ZFS 早 5 年用在文件系统里。
实践案例
案例 1:建一个池,开一个文件系统
# 三块盘做成 RAID-Z 池zpool create tank raidz /dev/sda /dev/sdb /dev/sdc
# 池里开文件系统(不用 mkfs,不用 mount)zfs create tank/photoszfs create tank/videos
# 看池子状态zpool status tank每个 zfs create 不预分空间,要多少给多少,和 Linux 传统的”先分区再 mkfs”完全反过来。
案例 2:快照真的零成本
zfs snapshot tank/photos@yesterday# ↑ 瞬间完成,不复制任何数据# COW 已经保证了旧块还在,快照只是"别 GC 它"
# 改了一通后想回滚zfs rollback tank/photos@yesterday为什么瞬间:快照不是复制,是”打个标记说这些块还有人引用”。普通 ext4 / XFS 快照要复制元数据,ZFS 因为 COW 已经天然保留旧版,只要给旧块多加一个引用计数。
案例 3:校验和救你于静默坏块
zpool scrub tank# ↑ 后台读全池,每个块对校验和# 发现某块在硬盘上被宇宙射线翻了一位 → 自动从冗余副本恢复传统 ext4 不知道数据是否还对,硬盘说”读到 X”它就信。ZFS 不信硬盘,信父块里那个独立校验和。
案例 4:克隆一个文件系统当沙盒
zfs snapshot tank/db@before-migrationzfs clone tank/db@before-migration tank/db-test# ↑ 克隆是可写快照,立即创建一份"独立的"文件系统# 实际只占改动部分的空间数据库迁移测试、容器分层都建立在这个能力上。Docker 早期的 layer 思路本质就是 ZFS clone 的简化版。
踩过的坑
-
吃 RAM 凶:去重特性需要把所有块的校验和存内存,1TB 数据约 5GB RAM。家用 NAS 默认要关 dedup。
-
扩容受限:传统认知”加块盘就扩容”在 ZFS 不成立——只能给 zpool 加新 vdev(一组盘),不能给现有 RAID-Z 加单盘。家用场景这点很难受,2023 年才有 RAID-Z expansion 补丁合入。
-
性能不如专用 FS:纯顺序读写场景 ZFS 比 XFS / ext4 慢 10-30%,因为校验和 + COW 有开销。要极致性能选别的,要数据完整性选 ZFS。
-
协议许可坑: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 年的遗憾
学到什么
- 不信任硬件——这是 ZFS 最颠覆的世界观。以前 FS 假设硬盘读啥给啥,ZFS 假设硬盘随时撒谎,每块都自己验
- 池化 + 按需分配 是把”管理容量”这件事从用户手里收回到系统的关键一步。后来云存储的”无限扩容”幻觉就建在这思路上
- 写时复制 = 快照零成本——这个等式被 ZFS 证明后,所有现代 FS / 数据库 / 区块链都在用
- 协议 + 时机 决定技术普及。ZFS 技术领先 10 年,但 CDDL 把它挡在 Linux 外,让 Btrfs / APFS 摘了桃子
延伸阅读
- 视频教程:ZFS Basics — Level1Linux(30 分钟把池/RAID-Z/快照过一遍)
- 官方白皮书:ZFS: The Last Word in Filesystems (Bonwick 2003)
- OpenZFS 文档:OpenZFS Docs(社区维护,最新特性都在这)
- lfs-1991 —— Log-Structured FS,ZFS 的 COW 思路精神祖父
- gfs —— Google File System,用另一条路(分布式)解决相似问题
关联
- 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 — 把整个磁盘当日志写