github编辑

ZFS 默认参数还不够好

ZFS 存储池创建最佳实践

在构建现代 NAS、海量数据存储或高性能虚拟化宿主机时,ZFS 是目前最强大的文件系统之一。然而,ZFS 的默认配置偏向于传统的 Unix 环境,直接使用默认命令建池往往无法发挥其在 Linux 下的最大潜力。

第一部分:创建命令

假设我们拥有 4 块硬盘,准备组建容错率为 2 块盘的 RAIDZ2 阵列:

步骤 1:创建根池

sudo zpool create -o ashift=12 \
    -O compression=zstd \
    -O atime=off \
    -O xattr=sa \
    -O dnodesize=auto \
    -O acltype=posix \
    -O canmount=off \
    tank raidz2 \
    /dev/disk/by-id/ata-WD_RED_1... \
    /dev/disk/by-id/ata-WD_RED_2... \
    /dev/disk/by-id/ata-WD_RED_3... \
    /dev/disk/by-id/ata-WD_RED_4...

步骤 2:创建数据集

sudo zfs create tank/data

执行完毕后,你的数据就可以安全地存入 /tank/data 目录了。

第二部分:为什么叫 tank

在几乎所有的 ZFS 官方文档和教程中,存储池的名字总是叫 tank

  1. 核心隐喻(水池与水箱):ZFS 的核心创新是抛弃了死板的分区,提出了“存储池(Storage Pool)”的概念。所有的底层硬盘汇聚成一汪可以流动的“水”(容量)。既然是 Pool(池子),那用来装载这些数据水流的容器,自然就是 Tank(水箱)。

  2. 《黑客帝国》的终极彩蛋:ZFS 诞生于 2001 年的 Sun 公司。当时电影《黑客帝国》(The Matrix)风靡硅谷。在电影中,主角飞船上那位负责管理所有数据流、加载虚拟环境程序的操作员,名字就叫 Tank。在当年早期的 ZFS 测试代码中,甚至还出现了 dozer(Tank 的哥哥)、neo(男主角)和 zion(人类家园)等命名。

  3. 极简主义tank 只有四个字母,全部在键盘左手区,没有任何数字,敲击极快,且在 Linux 枯燥的命名(如 vg0, md127)中极具辨识度。

第三部分:配置解析

1. 建池规则

  • 使用硬盘 ID (/dev/disk/by-id/...)

    • 原理:Linux 重启时,/dev/sda/dev/sdb 这样的盘符可能会发生漂移变化。使用全球唯一的硬盘物理 ID 建池,可以保证无论硬盘插在哪个接口,ZFS 都能准确无误地识别并导入阵列。

  • -o ashift=12(建池后不可更改!)

    • 原理ashift 决定了底层最小写入扇区大小(2^12 = 4096)。现代硬盘即使物理扇区是 4K,为了兼容老系统,也会向操作系统“谎称”自己是 512 字节。如果不强制设为 12,ZFS 会信以为真,导致每次写入都需要进行极度消耗性能的“读-改-写”操作。强制 ashift=12 可消除这种写放大,保护性能和硬盘寿命。注意这里是小写的 -o,代表 Pool 级别的底层属性。

2. 空间与性能

  • -O compression=zstd(透明压缩)

    • 原理:Zstandard 是目前最优秀的压缩算法。开启后,不仅凭空增加大量可用空间(文本、日志、虚拟磁盘等压缩率极高),而且由于写入物理硬盘的数据变少了,反而能提升整体的 I/O 吞吐速度

  • -O atime=off(关闭访问时间)

    • 原理:Linux 默认会在你每次“读取”文件时,向硬盘发起一次“写入”操作来更新访问时间。关闭它,让读取操作变成纯粹的只读,消除大量无谓的碎片化写入,大幅提升读取速度。

3. 小文件优化

在 Linux 下运行 ZFS(尤其是提供 SMB 共享或存储大量小文件时),以下三个参数必须绑定开启:

  • -O xattr=sa(扩展属性存入系统属性)

    • 原理:Linux 的扩展属性(如 SELinux 标签、Samba 权限)默认会被 ZFS 写在隐藏的独立目录中,导致每次读取都需要额外的磁盘寻道。设为 sa 后,这些属性会直接写在文件的 inode(dnode)内部,性能呈指数级提升。

  • -O dnodesize=auto(动态节点大小)

    • 原理:传统的 dnode 大小固定为 512 字节,如果复杂的权限属性塞不下,依然会导致性能下降。设为 auto 允许 ZFS 动态分配更大的 dnode 来一口气装下所有元数据。

  • -O acltype=posix(POSIX 访问控制列表)

    • 原理:启用高级权限控制。如果你需要为不同的用户组分配精细的权限,或者无缝对接 Windows 的 Samba 共享权限映射,这是必选项。

4. 拓扑设计

  • -O canmount=off(禁止挂载根节点)

    • 原理:这是最高级的设计模式。我们在 tank 上打满了各种优化配置,但禁止挂载 tank 本身。此时,tank 变成了一个纯粹的“属性模板(Container/Template)”。

    • 优势:随后我们通过 zfs create tank/data 创建子数据集时,tank/data自动继承 tank 的所有优化属性(除了 canmount 会恢复正常挂载)。这保证了数据绝对不会意外写进根目录,且未来可以轻松地创建拥有不同特性的平行数据集(例如单独建一个 tank/vm 并将块大小 recordsize 改为 64K 专门放虚拟机),实现互不干扰、干净清爽的存储拓扑。

最后更新于