ZFS 踩坑与优化
Table of Contents
1 ZFS Volume 不能作为 SWAP
使用 zvol 来创建 swap 可能会导致操作系统死锁。详见 https://github.com/openzfs/zfs/issues/7734 。
直到 2023 年这个 Bug 还没有修好。
2 ZFS Pool scrub 后 error 没有消失
执行 zpool scrub mymir1
进行全盘数据校验,校验过程中查看 zpool status -xv
是这样的:
pool: mymir1 state: ONLINE status: One or more devices has experienced an error resulting in data corruption. Applications may be affected. action: Restore the file in question if possible. Otherwise restore the entire pool from backup. see: https://openzfs.github.io/openzfs-docs/msg/ZFS-8000-8A scan: scrub in progress since Mon Aug 9 11:45:14 2021 1.62T scanned at 213M/s, 1.56T issued at 206M/s, 6.97T total 0B repaired, 22.36% done, 07:40:10 to go config: NAME STATE READ WRITE CKSUM mymir1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: Permanent errors have been detected in the following files: <metadata>:<0x0> <metadata>:<0x3d>
这个池按照 scrub -> export -> import -> scrub -> export -> import 流程走一遍。第一个 scrub 修文件,第二个 scrub 执行后 zfs 检测不到错误 errors 就没有了。
跟据 Richard Elling 的说法: zpool status
的 error buffer 包含最近两个 scrub 的结果信息。
因此,在删除异常的对象 ( 比如文件 ) 后,它仍然被列在错误缓冲区中。这时候用 zdb 查找 dataset+object tuple 找不到任何内容。所以要用两次 scrub 完全更新 error buffer 后, zpool status
才不会报错。
3 NFS 客户端以 sync I/O 的方式向 ZFS 写入数据时性能差
客户端通过 NFSv3 向 NFS 服务端的 ZFS 文件系统以 sync I/O 的方式写入数据时速度只有 18 MB/s,但内网速度是千兆,这速度显然没跑满网络带宽。
3.1 关闭 ZFS 的 sync I/O
在 NFS 服务器上执行 zfs get sync
可以看到所有 zfs 文件系统使用了 async 还是 sync:
NAME PROPERTY VALUE SOURCE mymir2 sync standard default mymir2/data sync standard default mymir2/videos sync standard default
sync 属性的取值可以为:
standard
: 默认值,是否同步取决于写操作请求。always
: 强制同步,高安全,低性能。disable
: 不同步,高性能,低安全。
数据读写方式为 sync 时 只有要写入的数据数据被真正地写入硬盘之后,才会返回写入成功信号 ,这就是问题所在。
执行 zfs set sync=disabled <zpool_name>/<zpool_zfs>
可以将 sync 模式关闭。
比如 zfs set sync=disabled mymir2/data
让 I/O 异步执行,速度就变快了。再执行 zfs get sync
可以看到:
NAME PROPERTY VALUE SOURCE mymir2 sync standard default mymir2/data sync disabled local mymir2/videos sync standard default
此时数据传输速度可以到相对正常的 70 MB/s 左右,在 50 - 77 MB/s 波动。
数据传输完毕建议把 I/O 方式改回 sync,毕竟异步读写的方式不是那么安全。
执行 sudo zfs set sync=standard <zpool_name>/<zpool_zfs>
可以恢复默认的 sync 模式。
比如,执行 sudo zfs set sync=standard mymir2/data
后再执行 zfs get sync
可以看到:
NAME PROPERTY VALUE SOURCE mymir2 sync standard default mymir2/data sync standard local mymir2/videos sync standard default
如果想把 SOURCE 字段也恢复原样,需要执行 sudo zfs inherit -rS sync <zpool_name>/<zpool_zfs>
,比如 sudo zfs inherit -rS sync mymir2/data
让 mymir2/data
的 sync 属性从父路径继承。再执行 zfs get sync
可以看到:
NAME PROPERTY VALUE SOURCE mymir2 sync standard default mymir2/data sync standard default mymir2/videos sync standard default
3.2 给 zpool 加独立 ZIL ( SLOG 组件 )
ZIL 和 SLOG 的描述可以读本站的 ZFS ZIL(SLOG) 组件 一文。
用于 ZIL 的设备应该是可以高速读写的 SSD,使用 4K 读写速度低下的 HDD 作为 ZIL 可能会降低整个 zpool 的性能。后文用 SLOG 设备 指代 具有 ZIL 功能的独立设备或分区 。
3.2.1 给没有 SLOG 设备的池添加一个 SLOG 设备
执行 zpool add <zpool_name> log <device>
可以为 <zpool_name>
添加 SLOG 设备,比如执行 zpool add mymir2 log /dev/da6p2
。
% zpool status pool: mymir2 state: ONLINE status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Sun Sep 19 17:58:44 2021 467G scanned at 46.7G/s, 467G issued at 46.7G/s, 2.58T total 0B resilvered, 17.70% done, 00:00:46 to go config: NAME STATE READ WRITE CKSUM mymir2 ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 da4 ONLINE 0 0 0 da5 ONLINE 0 0 0 errors: No known data errors % zpool add mymir2 log /dev/da6p2 % zpool status pool: mymir2 state: ONLINE status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Sun Sep 19 17:58:44 2021 467G scanned at 46.7G/s, 467G issued at 46.7G/s, 2.58T total 0B resilvered, 17.70% done, 00:00:46 to go config: NAME STATE READ WRITE CKSUM mymir2 ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 da4 ONLINE 0 0 0 da5 ONLINE 0 0 0 logs da6p1 ONLINE 0 0 0 errors: No known data errors
3.2.2 向已有一个 SLOG 设备的池添加另一个 SLOG 设备使之互为镜像
执行 zpool attach <zpool_name> <log_device> <device>
可以为 <zpool_name>
这个 pool 的 SLOG 设备创建镜像,比如 zpool attach mymir2 da6p2 /dev/da6p1
:
% zpool status pool: mymir2 state: ONLINE status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Sun Sep 19 17:58:44 2021 467G scanned at 46.7G/s, 467G issued at 46.7G/s, 2.58T total 0B resilvered, 17.70% done, 00:00:46 to go config: NAME STATE READ WRITE CKSUM mymir2 ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 da4 ONLINE 0 0 0 da5 ONLINE 0 0 0 logs da6p1 ONLINE 0 0 0 errors: No known data errors % zpool add mymir2 log /dev/da6p2 % zpool status pool: mymir2 state: ONLINE status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Sun Sep 19 17:58:44 2021 467G scanned at 46.7G/s, 467G issued at 46.7G/s, 2.58T total 0B resilvered, 17.70% done, 00:00:46 to go config: NAME STATE READ WRITE CKSUM mymir2 ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 da4 ONLINE 0 0 0 da5 ONLINE 0 0 0 logs mirror-1 ONLINE 0 0 0 da6p2 ONLINE 0 0 0 da6p1 ONLINE 0 0 0 errors: No known data errors
3.2.3 直接添加两个互为镜像的 SLOG 设备
执行 zpool add <zpool_name> log mirror <device_a> <device_b>
可以为 <zpool_name>
这个 pool 添加 SLOG 设备,并让两个设备互为镜像,比如 zpool add mymir2 log mirror /dev/da6p1 /dev/da6p2
。