外观
ZFS 入门:池、vdev 与内存占用
ZFS 在 PVE 里很好用,但它和你熟悉的 RAID 卡、LVM 都不一样。这篇讲清楚四件事:结构怎么组、内存怎么吃、快照怎么用、平时要做什么维护。
ZFS 的结构决定在建池那一刻
往已有的 RAIDZ vdev 里加盘、从池里移除 vdev,限制都很多(不同 OpenZFS 版本能力不同,且部分操作有前提条件)。建池前想清楚最终形态,这一点和 LVM 可以随时扩容完全不同。
结构:池、vdev、数据集
从下往上三层:
text
物理磁盘 → vdev(冗余在这一层) → pool(池) → 数据集 / zvolvdev 是冗余单位。一个 vdev 可以是:
| vdev 类型 | 需要几块盘 | 能坏几块 | 可用容量 |
|---|---|---|---|
| single | 1 | 0 | 全部 |
| mirror | 2+ | n-1 | 单块容量 |
| raidz1 | 3+ | 1 | (n-1) × 单块 |
| raidz2 | 4+ | 2 | (n-2) × 单块 |
| raidz3 | 5+ | 3 | (n-3) × 单块 |
池 由一个或多个 vdev 组成,数据在 vdev 之间条带分布。
池里任何一个 vdev 全废,整个池就废了
这是 ZFS 最容易被低估的风险。一个池里有两个 mirror vdev,其中一个 mirror 的两块盘同时坏了,整个池的数据都没了,包括另一个 mirror 上的。
所以:不要往一个池里混进没有冗余的 single vdev。
数据集 (dataset) 是池上的文件系统,zvol 是池上的块设备。PVE 给虚拟机磁盘用的是 zvol,给容器用的是数据集。
内存:ARC 会吃掉多少
ZFS 用 ARC(自适应替换缓存)做读缓存,放在内存里。默认情况下它会占用相当可观的一部分内存。
这会挤压客户机可用内存
PVE 上最典型的症状是:free -h 看着内存快满了,但你的虚拟机加起来没用这么多。ARC 确实会在内存紧张时归还,但归还有延迟,而且在内存分配的瞬时高峰上可能来不及。
在虚拟化宿主机上,建议主动给 ARC 设一个上限。
先看当前占用:
sh
arc_summary | head -30或者直接看数值(单位是字节):
sh
cat /proc/spl/kstat/zfs/arcstats | grep -E '^(size|c_max)'设置上限。下面把它限制到 8 GiB,请按你自己的内存总量调整(常见做法是给 ARC 留总内存的 10%–25%,同时不低于几个 GB):
sh
echo "options zfs zfs_arc_max=8589934592" > /etc/modprobe.d/zfs.conf
update-initramfs -u -k all这项改动需要重启才生效
zfs_arc_max 写进 modprobe 配置后,要重启宿主机(或重新加载 zfs 模块,实践中意味着卸载所有池,不现实)才生效。安排一个可以重启的窗口。
想立刻临时生效且不重启,可以写运行时参数,但重启后失效,只适合验证效果:
sh
echo 8589934592 > /sys/module/zfs/parameters/zfs_arc_max快照:便宜但会占空间
ZFS 快照是写时复制的,创建瞬间完成,几乎不占空间。但随着源数据变化,快照持有的旧数据块无法释放,占用会逐渐增长。
PVE 的虚拟机快照按钮在 ZFS 存储上就是走的这套机制。用起来很爽,代价是:
忘记删的快照是空间黑洞
「升级前打个快照」——然后三个月没删。期间虚拟机写入的每一个块,旧版本都被快照钉住了。池的可用空间就这么一点点消失。
查看快照占用:
sh
zfs list -t snapshot -o name,used,refer -s used定期清理不再需要的。
维护:scrub 和 SMART
ZFS 的核心优势是端到端校验:它能发现静默数据损坏,并在有冗余时自动修复。但这需要你定期跑 scrub(清理校验)。
PVE 安装 ZFS 时会自带一个定时任务(通常每月一次),确认它在:
sh
systemctl list-timers | grep zfs手动跑一次:
sh
zpool scrub <poolname>查看进度和结果:
sh
zpool status -v关注这些字段:
state: ONLINE—— 正常。DEGRADED表示有盘出问题但还能跑,FAULTED表示池不可用。errors: No known data errors—— 正常。scan:那一行显示上次 scrub 的时间和是否修复了错误。
DEGRADED 要当作紧急情况处理
池进入 DEGRADED 意味着冗余已经用掉了。这时候再坏一块(mirror 或 raidz1 的情况)数据就没了。立刻确认备份可用,然后尽快换盘。不要想着「还能跑就先这样」。
常用命令速查
sh
# 池状态与健康
zpool status
zpool list
# 容量(注意 ZFS 的可用空间计算和 df 不同)
zfs list
# 快照
zfs list -t snapshot
zfs snapshot <pool>/<dataset>@<name>
zfs destroy <pool>/<dataset>@<name>
# 属性(压缩、记录大小等)
zfs get compression,compressratio <pool>ZFS 的容量不能看 df
df 对 ZFS 的报数不准确(不考虑压缩、快照、预留)。用 zfs list 和 zpool list。注意这两个的数字也不一样:zpool list 是原始容量,zfs list 是考虑了冗余开销后的可用容量。
几个常见误区
「ZFS 需要 ECC 内存,否则会损坏数据。」 这个说法被夸大了。ECC 对任何文件系统都是加分项,不是 ZFS 的硬性前提。没有 ECC 照样可以用 ZFS。
「ZFS 每 TB 需要 1 GB 内存。」 这个经验法则来自去重(dedup)场景。不开去重的话不适用。而且——不要开去重,除非你非常清楚自己在做什么,它的内存代价极高。
「ZFS RAID 就是备份。」 不是。见本站反复强调的那句话:冗余防硬盘坏,备份防其他一切。
检查结果
在你的机器上跑一遍:
sh
zpool status # 应为 ONLINE,errors 为 No known data errors
zfs list # 确认可用空间
arc_summary | head -20 # 确认 ARC 占用在你的预期内
systemctl list-timers | grep zfs # 确认 scrub 定时任务存在四项正常,ZFS 这边就没有待办了。