Baidu Blog

Back

ZFS 介绍#

熟悉我的水友都知道,上一个 blog 站点之所以无了就是因为服务器转为 ZFS。

我记得老 blog 没有描述什么是 ZFS,所以今天就来和大家仔细分析一下 ZFS 是啥,以及我为什么选择使用 ZFS 在我的主服务器上。

结构#

ZFS 是最初由 Sun Microsystems 为 Solaris 开发的文件系统和卷管理器,现已作为 OpenZFS 项目在Linux等平台上持续发展。

传统上,我们可以将文件系统比作一位图书管理员,他知道每本书放在哪个书架上,但对书本的内容或书架本身的结构却一无所知。

如果书页发生粘连(数据损坏)或者书架本身出现问题(硬件故障),这位管理员可能束手无策。

然而,ZFS(Zettabyte File System)彻底改变了这一模式。它更像是一位集图书馆建筑师、图书管理员和书籍装订师于一身的全能专家。

ZFS 不仅知道数据的位置,还理解其底层物理存储(磁盘)的结构布局,并时刻检验着每一页数据(数据块)的完整性。

与传统存储栈将 RAID、卷管理和文件系统分层设计不同,ZFS 将 RAID 控制器、卷管理和文件系统融为一体,提供一个统一的存储池(Storage Pool)管理数据。

这一整合意味着操作系统直接对接 ZFS 存储池,避免传统多层栈各层之间信息隔离造成的低效和风险。

ZFS的存储架构可以被看作一个三层金字塔 :

  1. 物理磁盘 (Physical Disks):这是最底层,即服务器中的实际硬件,如 HDD(机械硬盘)或 SSD(固态硬盘)。
  2. 虚拟设备 (vdev - Virtual Device):vdev 是 ZFS 的基本构建块。它由一个或多个物理磁盘组成,并定义了这些磁盘的数据组织和冗余方式。一个 vdev 可以是一个单独的磁盘,也可以是一个镜像组或一个 RAID-Z 阵列。
  3. 存储池 (zpool - Storage Pool):zpool 是最高层级的存储容器,它由一个或多个 vdev 组成。一旦 zpool 被创建,其全部存储空间就可以被池内的所有文件系统(在 ZFS 中称为数据集)共享使用,无需预先划分分区。

安全#

所有的数据冗余和故障容错都在 vdev 层面实现 。选择何种 vdev 类型,直接决定了存储池的性能、可用容量和数据安全性。

  • 条带化/单一磁盘 (Stripe/Single-disk):这是最简单的 vdev,可以由单个磁盘构成,也可以由多个磁盘组成一个无冗余的条带集(类似于 RAID 0)。数据块会被轮流写入 vdev 中的所有磁盘,可以最大化性能和容量,但没有任何容错能力。任何一个磁盘的故障都会导致整个 vdev 失效。
  • 镜像 (Mirror):镜像 vdev 类似于 RAID 1,它将相同的数据完整地写入 vdev 中的每一个磁盘。一个双向镜像 vdev 可以承受一个磁盘的损坏,只要还有一个磁盘健康,数据就不会丢失。ZFS的镜像比传统 RAID 1 更灵活,支持创建三向甚至更多路的镜像,以提供更高级别的冗余 。镜像 vdev 的写入性能约等于单个磁盘,但读取性能可以随磁盘数量线性扩展,因为所有磁盘都可以同时响应读取请求。这使得它在需要高 IOPS(每秒读写操作次数)的场景下表现出色。
  • RAID-Z:这是 ZFS 对传统奇偶校验 RAID(如 RAID 5 和 RAID 6)的创新性替代方案。传统 RAID 5 存在一个被称为“写洞(Write Hole)”的严重缺陷:如果在写入数据和奇偶校验位的过程中发生断电,可能导致数据和奇偶校验位不一致,而在后续重建时,这种不一致可能会永久性地破坏数据。ZFS 通过其写时复制(Copy-on-Write)机制,从根本上解决了这个问题。RAID-Z 总是写入全新的条带,而不是覆写旧的,从而保证了操作的原子性。RAID-Z 有三种级别 :
    • RAID-Z1:类似于 RAID 5,使用一个磁盘的容量存储奇偶校验信息,允许 vdev 中任意一个磁盘损坏。
    • RAID-Z2:类似于 RAID 6,使用两个磁盘的容量存储奇偶校验信息,允许 vdev 中任意两个磁盘损坏。
    • RAID-Z3:提供三重奇偶校验,允许 vdev 中任意三个磁盘损坏,提供了极高的冗余度。

写时复制 COW#

在传统文件系统中,当修改一个文件时,系统会直接在存储该文件的旧数据块上写入新数据。

如果在写入过程中发生意外(如断电),旧数据可能已经被部分覆盖,而新数据又未完全写入,导致数据块损坏。

ZFS 则完全不同。它从不覆写活动数据。当一个数据块需要被修改时,ZFS 会执行以下步骤 :

  1. 将修改后的新数据写入到磁盘上的一个全新的、未被使用的位置。
  2. 修改指向该数据块的父级元数据指针,使其指向这个新写入的位置。
  3. 这个指针的更新操作是“原子性”的,意味着它要么完全成功,要么完全不发生。

这个过程确保了文件系统始终处于一致的状态。

如果在写入新数据块或更新指针的任何时刻发生断电,旧的数据块和指向它的旧指针仍然完好无损。

系统下次启动时,会发现未完成的写入事务,并简单地将其丢弃,文件系统状态回滚到写入操作开始前的那个一致性时刻。

正是由于这个机制,ZFS 不需要传统的 fsck(文件系统检查)工具来修复损坏。

快照#

ZFS 的快照(snapshot)功能是 COW 机制最直接、最强大的应用之一。快照是对一个文件系统或卷在特定时间点的只读副本。

当创建一个快照时,ZFS 并不会复制所有数据。它做的仅仅是“冻结”当前文件系统的元数据指针树。因为 COW 机制保证了旧的数据块不会被覆写,快照只需保留对这些旧数据块的引用即可。

因此,创建快照是瞬间完成的,并且在初始状态下几乎不占用任何额外的存储空间 。只有当活动文件系统中的数据被修改时,快照才会开始“消耗”空间。

修改操作会写入新的数据块,而旧的数据块因为被快照引用而不会被释放。

快照所占用的空间,就是这些被活动文件系统修改或删除后,但仍被快照引用的旧数据块的总和。

绝不信任#

ZFS 的设计哲学是“永不信任硬件”。它假定硬件(内存、线缆、磁盘控制器、磁盘本身)随时可能出错,并因此构建了一个端到端的、多层次的数据完整性保护体系。

端到端#

ZFS的核心保护机制是端到端校验和(end-to-end checksums)。

当数据写入时,ZFS 会为每一个数据块和元数据块计算一个校验和(默认为高度优化的fletcher4 算法,也可选 sha256 等加密哈希算法)。

当数据被读取时,ZFS 会重新计算校验和并与存储的值进行比对。如果不匹配,即数据已经损坏。

ZFS 的校验和机制之所以如此强大,关键在于它如何存储这些校验和。

ZFS 将整个文件系统组织成一棵巨大的默克尔树(Merkle Tree),也称为哈希树。

在这棵树中,一个数据块(子节点)的校验和,并存储在该数据块旁边,而是存储在指向它的父节点的指针中。

这个父节点本身也是一个数据块,它的校验和又存储在它的父节点的指针中,以此类推,一直追溯到文件系统的根节点,即“超级块(uber block)”。

这种结构形成了一条“信任链”。

想象一下,传统文件系统将数据和它的校验和存放在同一个磁盘扇区。如果一个有缺陷的磁盘控制器错误地写入了整个扇区,那么数据和校验和会同时被破坏,校验机制也就失效了。

而 ZFS 通过将校验和“向上一级”存储,确保了用于验证数据的元数据本身也受到上层元数据的验证。要无声地破坏一个数据块,攻击者不仅需要篡改数据块本身,还需要篡改其父指针中的校验和,然后是祖父指针中的校验和,一路向上,直至根节点,这在现实中几乎是不可能的。

自保#

ZFS 的数据完整性不仅限于检测错误,更在于自我修复(self-healing)

当 ZFS 在读取数据时检测到校验和不匹配的错误,并且该数据所在的 vdev 具有冗余(例如,是一个镜像vdev或RAID-Z vdev),它会执行以下操作 :

  1. 从冗余副本(另一个镜像盘或通过奇偶校验重构)中获取正确的数据。
  2. 将正确的数据返回给发出读取请求的应用程序,整个过程对应用透明。
  3. 同时,使用正确的数据覆写磁盘上的损坏副本,从而“治愈”错误。

然而,有些数据可能写入后很长时间都不会被读取,它们同样面临着因介质老化而导致的“比特衰减”(bit rot)风险。

为了主动发现并修复这类潜在的静默数据损坏,ZFS 提供了一个名为**巡检(scrub)**的后台进程。

zpool scrub 命令会遍历存储池中的每一个数据块,读取它,验证其校验和,并在必要时进行修复。定期(例如每月一次)执行 scrub 是维护 ZFS 存储池长期健康的关键。

但需要注意,一个没有冗余的 ZFS 池虽然能检测到数据损坏,但无法进行自我修复。

性能#

ZFS集成了一套复杂而高效的缓存和日志机制,以优化在不同工作负载下的读写性能。

读取#

ZFS的读取性能主要依赖于其位于内存中的自适应替换缓存(Adaptive Replacement Cache, ARC)

  • ARC:与传统的 LRU(Least Recently Used)缓存不同,ARC 是一种更智能的缓存。它同时跟踪“最近使用”和“频繁使用”的数据,并动态调整两者的缓存空间分配,以达到更高的缓存命中率。ZFS 默认会使用高达 50% 的系统物理内存作为 ARC,因为在存储系统中,内存是提升性能最有效的。
  • L2ARC (Level 2 ARC):当系统内存有限,而需要频繁访问的热数据集体积又大于 ARC 所能容纳的大小时,可以添加一个二级 ARC,即 L2ARC。L2ARC 通常配置在高速 SSD 上,用作从 ARC 中被淘汰数据的中转站。当 ARC 需要空间时,它会将一些数据块驱逐到 L2ARC 中,而不是直接丢弃。这样,如果这些数据块很快被再次请求,就可以从速度远快于机械硬盘的 L2ARC中读取,而无需访问主存储池。

然而,L2ARC 与 ARC 之间存在寄生的关系。

L2ARC 本身需要一部分 ARC(即内存)来存储其内容的索引 。

如果添加一个非常大的 L2ARC,其索引可能会占用大量宝贵的内存,从而挤占了本可以用于缓存数据本身的 ARC 空间,最终可能导致整体性能不升反降。

因此,性能优化的黄金法则是:优先增加系统内存以扩大 ARC。只有在内存已达上限,且ARC命中率仍然不高的情况下,才应考虑添加L2ARC。

写入#

ZFS的写入处理区分同步写入和异步写入,并为此提供了专门的日志机制。

  • 异步写入 (Asynchronous Writes):这是大多数常规文件操作(如复制文件)的默认模式。数据被写入内存(ARC)后,系统立即向应用程序返回“写入完成”的确认。ZFS 稍后会在一个事务组(Transaction Group, TXG)中,将内存中的多个写入操作批量、高效地刷入磁盘。这种方式性能极高,但代价是在断电时可能会丢失最后几秒钟尚未写入磁盘的数据。
  • 同步写入 (Synchronous Writes):某些应用(如数据库、NFS 服务器)要求数据必须被安全地写入到持久性存储后,才能确认写入完成。为满足这一要求,ZFS 使用了 ZFS 意图日志(ZFS Intent Log, ZIL)。当收到一个同步写入请求时,ZFS 会先将该写入操作记录到 ZIL 中,然后才向应用确认。ZIL 就像一张“待办清单”,记录了所有已确认但尚未完全合并到主存储池中的写入操作。
  • SLOG (Separate Log device):默认情况下,ZIL 存储在主存储池的磁盘上。对于同步写入密集型负载,这意味着每次写入都需要在主池的慢速磁盘上进行一次小的随机写入,这会成为性能瓶颈。为了解决这个问题,用户可以添加一个独立的、高速的日志设备(SLOG),通常是 NVMe SSD 或 Intel Optane 等低延迟设备 。当配置了 SLOG 后,ZIL 就会被存放在这个高速设备上。同步写入操作可以极快地提交到 SLOG,系统可以迅速返回确认,从而大幅提升性能。

**SLOG 只对同步写入有效!**对于绝大多数家庭用户或媒体服务器的异步写入负载,SLOG 完全不会被使用,添加它纯属浪费。

因此,在投资昂贵的 SLOG 设备之前,必须首先确定自己的工作负载是否确实以同步写为主。

代替#

尽管ZFS功能强大,但它并非适用于所有场景的唯一解决方案。在开源和商业领域,都存在着具有不同设计哲学和优缺点的替代方案。

特性 (Feature)ZFSBtrfsLVM + ext4/XFS
架构 (Architecture)统一卷管理器与文件系统 (Unified)统一卷管理器与文件系统 (Unified)分层 (Layered)
数据完整性 (Data Integrity)端到端校验和 (End-to-end checksums)数据块校验和 (Per-block checksums)无 (文件系统层面)
自我修复 (Self-Healing)是 (需冗余配置)是 (需冗余配置)
RAID稳定性 (RAID Stability)极佳 (RAID-Z1/2/3)镜像/RAID10: 良好; RAID5/6: 不稳定极佳 (通过mdadm)
快照 (Snapshots)高效, 基于数据集高效, 基于子卷低效, 基于块
存储池扩展 (Pool Expansion)僵化 (添加vdev, 而非单个磁盘)非常灵活 (添加/移除单个磁盘)灵活 (向卷组添加磁盘)
资源占用 (Resource Usage)高 (特别是内存)中低
内核集成 (Kernel Integration)外部模块 (Out-of-tree module)原生 (Native)原生 (Native)

*表由 Gemini 2.5 Pro 生成

功能/特性ZFS (OpenZFS)BtrfsXFSExt4 + LVM
快照支持(原生快照与克隆,开销极小)支持(原生快照,基于子卷)不支持*(需通过 LVM 等卷管理创建块级快照)不支持*(需通过 LVM 创建快照卷)
数据校验和有 – 数据与元数据端到端校验,读写均验证,自动修复有 – 数据/元数据校验,可配合RAID自愈元数据CRC校验;无用户数据校验元数据CRC校验;无用户数据校验
内置 RAID有 – 内建 RAID-Z1/2/3(类似RAID5/6),支持镜像有 – 内建多种 RAID (0,1,5,6,10)无 – 需借助 mdadm 等软RAID 或硬件RAID无 – 需使用 mdadm (软件RAID) 等实现
透明压缩有 – 支持 LZ4、Zstd 等压缩有 – 支持 Zstd、LZO 压缩
重复数据删除有 – 支持实时重删(需足够内存), 可选开启有 – 提供离线重删工具(手动运行)
卷管理功能有 – 集成卷管理,存储池可弹性扩展部分支持 – 可管理多设备(但无独立卷组概念)无 – 需独立的 LVM 提供有 – LVM 实现卷弹性(独立于 ext4 文件系统)
内存需求高 – 推荐 ≥8GB 内存 (大量缓存加速IO)中等 – 相比ZFS占用更少,嵌入内核开销低低 – 内存占用很小低 – Ext4 占用低,LVM 开销也很小
性能表现综合性能好;大量内存下吞吐可接近甚至超过 ext4 ;小随机写略有延迟(CoW和校验开销)表现良好;高负载或碎片多时性能下降 ;并发读写性能次于XFS但可接受极佳顺序和并发性能;擅长大文件和多线程IO ;删除海量小文件速度较慢非常出色的通用性能;小文件读写和元数据操作效率高;额外的LVM层对性能影响可忽略
数据完整性极高 – 端到端校验,每次读写均验证;镜像/奇偶冗余下自动纠错高 – 校验可发现损坏;有冗余时可自我修复错误一般 – 仅保护元数据结构,无法检测或修复文件内容损坏一般 – 元数据有校验;文件内容损坏需依赖底层RAID发现
成熟度非常成熟 – 十多年企业级验证,社区活跃较成熟 – 内核直供,多发行版已用作默认FS(如SUSE);部分功能尚在改进非常成熟 – 历史悠久,大规模部署广泛,RHEL默认FS之一非常成熟 – Linux默认FS,稳定性业界公认
运维复杂度较高 – 需学习专有概念和命令,调优选项多 ;与发行版集成都需特别注意中等 – 基本用法简单如常规FS,高级功能略有学习成本低 – 文件系统本身简单易用;需另行管理RAID/LVM增加复杂度中等 – Ext4 使用简单;LVM/RAID 层增加了配置步骤

*表由 ChatGPT 5 生成

除了开源的之外,还有一些商业闭源的类似于

  • Storage Spaces
  • Veritas VxVM
  • Oracle ASM
  • NetApp ONTAP
  • Dell PowerScale (原 Isilon OneFS)
  • Veritas InfoScale

还是挺多的。

结论#

因为我的主服务器拥有 96G ECC RAM,所以最终选择了 PVE 自带的 ZFS 方案。

在一次很抽象的删除了文件之后,并通过快照恢复后。ZFS 就成了我的最爱了,所以如果水友们也有大内存,那么非常推荐各位尝试使用一下 ZFS。

由于写网文写多了,分段可能有点奇怪,请各位见谅,那么至此,ZFS 就算给大家深入浅出的介绍完毕了,祝大家玩鸡愉快,我们下一篇文章再见👋

ZFS 介绍
https://baidu.blog.icechui.com/zh/blog/p/zfsintro
Author baidu0com
Published at August 18, 2025