MENU

【歪门邪道】Unraid上的ZFS初体验

April 1, 2025 • 瞎折腾

原本打算组完NAS之后慢慢扩容,这正好也是Unraid的优势所在。可是计划永远赶不上变化,我朋友扩容了他的NAS,换下来了3块8TB和2块6TB的硬盘,我想着与其去网上买来路不明的二手硬盘,不如就把我朋友换下来的硬盘收了。于是乎掐指一算,我之前自己买的2块,加上收来的5块,正好7块,马上就要把我的8盘位吃满了。想来想去,不如折腾个ZFS吧!

前言

先前我在文章里提过没有选择TrueNAS是因为DDR5 ECC平台太贵了,而且没有小主板。后来我也仔细查阅了不少资料,最终得出的结论是ECC会让内存变得更安全,但是没有ECC并不意味着ZFS会变得脆弱。正相反,其实ZFS从设计上就是为了尽最大努力保证它读出来的数据要和你当初交给它时一致。

顺带一提,我今天才知道ZFS也是Sun公司制作的。我越发觉得这个公司真的很酷,没有坚持到现在真的很遗憾。没错,不要怀疑自己,Java也是这个公司搞的。虽然Java本身的语法和其衍生品相比并不酷,但JVM很酷,它作为一个平台支持了其他更酷的东西,比如kotlin、scala这些语言。而ZFS最初于2001年开始研发,它的目的就是不相信任何存储设备,因此ZFS也包含了大量措施来检测数据完整性,如果ZFS没有100%的把握确定它交给你的数据是正确的,它就不会稀里糊涂的把数据给你,而是通过报错让你知道系统出问题了。太酷了!

尽管Unraid的阵列在扩展性和易用性上都比ZFS好,可最大的问题就是它无法甄别出现问题时哪块盘或者哪个文件出问题了,这也是我自己编写文件校验工具的动机。虽然大部分情况下硬盘要坏都是有征兆的,比如频繁报错、smart自检失败、掉盘等,但有一种错误是静悄悄的:bit rot。折腾NAS的玩家应该对这个词并不陌生,它描述了一种存储介质的一种物理翻转,也就是说硬盘在没人动它的情况下,可能某一位就会自己从0翻转到1,或者反过来。原因嘛,可能是生产瑕疵,或者是宇宙射线恰好命中了你的硬盘,又或者过年的时候亲戚家的熊孩子拿着强力磁铁吸你的NAS机箱。总之这种物理的问题完全无法避免,而这种又不算硬盘故障,诸多自检都对此无能为力。当你访问到了包含bit rot的区块,硬盘控制器自己也不知道这里的数据出问题了,它只能忠实地将它从磁盘上读出来的数据写到总线上,进而由操作系统呈现给用户,直到用户发现他珍藏多年的家庭合影再也打不开了。

对于Unraid来说,定期计算磁盘校验有助于发现这种错误,比如当bit rot发生时,unraid可能会注意到阵列读出来的数据计算出的校验位和校验盘中存储的不一致,这个时候用户有两种选择:查找问题,或者将新的校验位写入校验盘。即便有两块校验盘也无法确定到底是哪块盘的数据出问题了,甚至你都无法得知是哪个文件出问题了——这就是我自己写文件校验工具的目的,虽然校验和本身也存在硬盘上,也有遭受bit rot的风险,但密码学领域的哈希计算确保了任何一点微小的改动(哪怕只有1bit)也会导致计算出和原来完全不同的哈希。因此在很大概率上可以通过文件级别的哈希来发现错误,然后从备份中找到完好的文件然后恢复。

是的,无论是Unraid、RAID还是ZFS都不能替代备份。尽管ZFS有更强大的数据完整性校验和自恢复功能,如果数据损坏超过一定程度,ZFS也无力回天,而且它还会拒绝给你不完整的数据,因此拥有一个备份是十分必要的。

当然,很大概率并不意味着万无一失。如果恰好出现多个bit rot使得奇偶校验没变,而其中一些bit rot又出现在一个同一个文件,恰好导致了哈希冲突,那么恭喜你:这虽然不是什么露脸的事儿,但确实非常稀有,值得你向那些搞IT运维的人还有用NAS不做备份的人炫耀,坏事是会发生的。为了确保万无一失,我还是要考虑ZFS。ECC内存的问题解决了,下面就要考虑扩展和易用的问题了。易用性在Unraid支持了ZFS之后变得好了许多,你可以直接通过网页面板来扩容和管理ZFS存储池,配合插件ZFS Master for Unraid来管理ZFS的dataset和快照。扩容嘛,正好我是3块8TB,2块6TB,再去买一块6TB,刚好做两个3盘raidz1的vdev。

什么?你问vdev是什么?简单地说,在ZFS里面,最顶层的结构是zpool,也就是一个存储池,但是和群辉以及lvm中存储池的概念不同,ZFS的zpool是由vdev组成的。所谓vdev就是virtual device,虚拟设备。这些虚拟设备是由多个硬盘在不同配置下组成的。比如说你可以用两块硬盘按照mirror模式组成vdev,这和传统的raid1差不多。你也可以用stripe模式组成类似raid0效果的vdev,或者用ZFS独家的raidz(1,2,3)来确保vdev在丢失1、2、3块硬盘的情况下还能够读出数据。当然,ZFS中vdev的种类也有所不同,比如数据vdev用来存储你的文件,而元数据vdev则可以用来记录ZFS这个文件系统的数据。我的使用场景没有这么复杂,况且unraid也没有支持那么复杂的场景,因此我就只用数据vdev。

那么,话不多说,我们直接开始操作。

创建zpool

创建zpool其实挺简单的,首先要停掉阵列,然后创建新的pool。起名是最难的,我想来想去,就叫它zfs-pool吧。添加好我的3块8TB硬盘之后,点击左边的Zfs-pool就可以进入池的设定页面。在文件系统里选择zfs或者zfs - encrypted,我选择的后者,和我的阵列一样,硬盘要先加密再使用。注意这里的zfs - encrypted和ZFS内置的加密还不一样。Unraid的加密文件系统是使用的LUKS,对设备进行块级加密之后再交给文件系统使用。而ZFS内置的加密则是将数据写入磁盘之前进行加密。这两种加密互不冲突,但同时启用会影响性能。鉴于我已经使用了加密阵列,因此我选择了让unraid帮我处理加密。选择完文件系统,我们可以选择分配方式了,我这里选了raidz1,这样启动阵列之后就会创建一个3盘的vdev,使用一块盘的容量进行冗余,读取速度则相当于是两块盘的总和。由于我后来购买的6TB盘还没到,因此他们留作后续扩容。

启动阵列,会发现unraid提示zfs pool不可用,因为你还没有格式化。去到页面最底下格式化一下就好了。至此,我们算是有一个zfs存储池可以用了。

但是还没完!确保ZFS能对所有所有数据都能够自恢复,我们需要配置一个叫做scrub的东西,它会定期检查所有数据,然后修复错误的地方,有点类似于unraid的校验。在阵列启动的时候点进Zfs-pool,可以找到scrub设置,可以设置每周或每月定期运行。

此外,为了节省一些空间,我还决定打开zfs的压缩和dedup功能。压缩可以直接在网页端设置,但dedup需要使用命令行:

zfs set dedup=blake3,verify zfs-pool

这个命令会在zfs-pool这个存储池启用去重,算法使用blake3计算哈希,而verify标志则是告诉zfs当两个块哈希相同的时候,逐个字节对比块内数据。

完成设置之后就可以在share里面使用新创建的存储池了。在新版本unraid里面,zfs存储池可以用作一级或者二级缓存,这里我选择还是沿用NVME的cache作为写入缓存,然后使用mover移动到zfs-pool,因为我的内存不是很大,所以写缓存还是要靠SSD。

需要注意的是更新的share的选项之后,原本的文件并不会从阵列自动复制过去。如果要手动复制的话,建议先复制到SSD上,然后再调用mover,这样mover会自动按照share创建dataset。否则直接复制上去就是文件夹,而后续通过ZFS Master创建dataset就会被挂载点覆盖。不过万一被覆盖了也不要慌,因为数据没有丢。使用zfs unmount /mnt/zfs-pool/<mount-point>来卸载对应的挂载点,然后把被覆盖的文件夹重命名,然后再使用zfs mount zfs-pool/<mount-point>来重新挂载对应的dataset,之后用rsync把文件复制过去就好了。

扩容(新增vdev)

由于是开始折腾ZFS当晚就下单了新的硬盘,因此没几天就到了,正好试一下给ZFS扩容。一般来说给ZFS扩容有两种方法,第一种就是新增数据vdev,因为vdev之间是以stripe的方式组合的,所以新的vdev容量是按照加法计算进存储池的。第二种就是原地扩容vdev,但是你需要把vdev里所有的硬盘都扩大才行,并且只能扩容,不能缩小。后者也是为什么我选了两个3盘z1,而不是一个6盘z2。三盘在升级的时候带来的经济压力会稍微小一些,虽然vdev可以接受大小不一的盘,但是对于容量超出其他盘的部分就完全浪费了。

扩容的操作也相对简单,停掉阵列,将原本Zfs-pool的slots从3改成6,然后选中新的硬盘,启动阵列后便会自动创建一个新的vdev。在命令行中可以确认:

# zpool list -Pv zfs-pool 
NAME                   SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
zfs-pool              38.2T  4.88T  33.3T        -         -     1%    12%  1.00x    ONLINE  -
  raidz1-0            21.8T  4.88T  17.0T        -         -     2%  22.3%      -    ONLINE
    /dev/mapper/sdf1  7.28T      -      -        -         -      -      -      -    ONLINE
    /dev/mapper/sdh1  7.28T      -      -        -         -      -      -      -    ONLINE
    /dev/mapper/sdc1  7.28T      -      -        -         -      -      -      -    ONLINE
  raidz1-1            16.4T  6.05M  16.4T        -         -     0%  0.00%      -    ONLINE
    /dev/mapper/sdb1  5.46T      -      -        -         -      -      -      -    ONLINE
    /dev/mapper/sdd1  5.46T      -      -        -         -      -      -      -    ONLINE
    /dev/mapper/sdi1  5.46T      -      -        -         -      -      -      -    ONLINE

这里由于我使用了unriad的luks加密,所以设备全都是解密后的mapper。但这里可以看到多了一个raidz1-1的vdev,里面就是新添加的三块6TB的硬盘。

至此,在unraid上建立zfs的过程就到此结束了。

-全文完-


知识共享许可协议
【歪门邪道】Unraid上的ZFS初体验天空 Blond 采用 知识共享 署名 - 非商业性使用 - 相同方式共享 4.0 国际 许可协议进行许可。
本许可协议授权之外的使用权限可以从 https://skyblond.info/about.html 处获得。

Archives QR Code
QR Code for this page
Tipping QR Code