字数 1706,阅读大约需 9 分钟
压缩、加密、配额,这三个特性是 ZFS 的"杀手锏",在 LVM + ext4 中要么没有、要么需要外部工具。ZFS 一行命令搞定。
一、压缩(Compression)
1.1 压缩算法
ZFS 支持的压缩算法:
| | | |
|---|
off | | | |
lz4 | | | |
lzjb | | | |
zstd | | | |
zstd-fast | | | |
gzip | | | |
gzip-1 | | | |
zle | | | |
1.2 启用压缩
# 设置压缩(默认 lz4)
$ zfs set compression=lz4 tank/data
# 高压缩比(用于冷数据)
$ zfs set compression=zstd-9 tank/archive
# 关闭
$ zfs set compression=off tank/data
1.3 压缩对性能的影响
常见误解:压缩 = CPU 开销 = 慢
事实:
- • LZ4:CPU 极快(5+ GB/s),对现代 CPU 来说几乎免费
- • 实际场景下 LZ4 经常提升性能(因为写更少的数据 → IO 更快)
- • 数据库(已压缩的块)反而会被 LZ4 浪费一些 CPU
经验:
1.4 看压缩效果
# 看压缩率
$ zfs get compressratio tank/data
NAME PROPERTY VALUE SOURCE
tank/data compressratio 1.84x -
# 1.84x 表示压缩后体积是原始的 1/1.84
1.5 改压缩的注意事项
compression 可以随时切换,已存在的数据不会自动重压缩,只有新写入的数据会用新算法。
要重压缩已存在数据:
# 用 zfs send/recv + 新属性
$ zfs send tank/data@before | zfs recv -o compression=zstd tank/data-new
$ zfs destroy tank/data
$ zfs rename tank/data-new tank/data
二、加密(Encryption)
OpenZFS 2.0+ 原生支持加密。在 OpenZFS 之前,ZFS 上加密需要 LUKS(Linux)或 geli(FreeBSD)。
2.1 创建加密 dataset
# 创建时加密
$ zfs create -o encryption=aes-256-gcm -o keylocation=prompt -o keyformat=passphrase tank/encrypted
Enter passphrase: ********
Verify passphrase: ********
# 用密钥文件
$ dd if=/dev/urandom of=/etc/zfs/key-tank bs=32 count=1
$ chmod 0400 /etc/zfs/key-tank
$ zfs create -o encryption=aes-256-gcm \
-o keylocation=file:///etc/zfs/key-tank \
-o keyformat=raw \
tank/encrypted
2.2 加密算法
# 查看支持的加密算法
$ zfs get -o name,property,value encryption
常用:
| | |
|---|
aes-256-gcm | | |
aes-256-ccm | | |
aes-128-gcm | | |
2.3 加载 key
# 手动加载
$ zfs load-key tank/encrypted
# 用密钥文件
$ zfs load-key -L file:///etc/zfs/key-tank tank/encrypted
# 卸载 key(数据不可访问)
$ zfs unload-key tank/encrypted
2.4 自动加载
# 重启时自动从密钥文件加载
# /etc/zfs/zed.d/zed.rc 或 systemd service
$ zfs set keystatus=available tank/encrypted
$ zfs set keylocation=file:///etc/zfs/key-tank tank/encrypted
生产推荐:
- 1. 密钥文件放 TPM2 上(
systemd-cryptenroll) - 2. 或者用 网络密钥服务(HashiCorp Vault 等)
- 3. 永远不要在
keylocation=prompt 下重启(卡在启动)
2.5 加密与性能
- •
aes-256-gcm 用 AES-NI 硬件加速,性能损失 < 5% - • 没有 AES-NI 的旧 CPU 会慢 20~30%
2.6 加密的局限
- • 加密 dataset 不能直接 zfs send 给未加密 dataset(必须 rekey)
# 看加密层级
$ zfs get -r encryption,keylocation tank
三、配额(Quota)
ZFS 的配额有四组:
| | |
|---|
quota | | |
refquota | | |
reservation | | |
refreservation | | |
3.1 硬上限:quota
# 给 alice 限制 10G(含快照)
$ zfs set quota=10G tank/home/alice
# 用户写入超过 10G 会失败
$ cp largefile /tank/home/alice/
cp: cannot create regular file 'largefile': Disk quota exceeded
3.2 不算快照的硬上限:refquota
# alice 的"主数据"上限 10G,快照另算
$ zfs set refquota=10G tank/home/alice
3.3 预占空间:reservation
# 重要业务预留 50G
$ zfs set reservation=50G tank/db
# 其他 dataset 不会消耗这 50G
$ zfs list -o name,used,reservation,available tank
reservation 保证即使 pool 满,这个 dataset 也有空间。
3.4 看配额使用
# 看 dataset 的 used
$ zfs get used,quota,refquota,reservation tank/home/alice
# 多个 dataset 概览
$ zfs list -o name,used,quota,refquota,available,reservation
3.5 多用户配额管理
# 给每个用户建独立 dataset
$ zfs create -o quota=20G tank/home/alice
$ zfs create -o quota=30G tank/home/bob
$ zfs create -o quota=50G tank/home/charlie
# 一行命令看所有用户用量
$ zfs list -o name,used,quota -r tank/home
3.6 配额嵌套规则
- • 但子 dataset 实际可用空间受双重限制:自己 quota + 父 quota 剩余
$ zfs set quota=100G tank/home
$ zfs set quota=80G tank/home/alice
# tank/home/alice 最大能用 80G(即使 tank/home 还有 100G)
四、用户组配额(User/Group Quota)
ZFS 也支持 用户级和组级配额:
# 设置用户配额
$ zfs set userquota@alice=10G tank/home
$ zfs set userquota@bob=20G tank/home
# 设置组配额
$ zfs set groupquota@developers=100G tank/projects
# 查看
$ zfs userspace tank/home
$ zfs groupspace tank/projects
五、综合实战
场景:家用 NAS 部署
# 1. 创建主 pool
$ zpool create tank mirror /dev/sdb /dev/sdc
# 2. 顶层结构
$ zfs create -o compression=lz4 -o atime=off tank/data
$ zfs create -o compression=lz4 -o recordsize=1M tank/media
$ zfs create -o compression=zstd tank/documents
$ zfs create -o compression=off tank/database
# 3. 用户目录
$ zfs create -o quota=100G -o compression=lz4 tank/home
$ zfs create -o quota=50G tank/home/alice
$ zfs create -o quota=100G tank/home/bob
# 4. 加密私密数据
$ zfs create -o encryption=aes-256-gcm \
-o keylocation=file:///etc/zfs/key-private \
-o keyformat=raw \
tank/private
# 5. 快照策略(用 sanoid / zfs-auto-snapshot)
$ zfs create -o canmount=off tank/snapshots
场景:企业数据库
# 主数据:高性能
$ zfs create -o compression=off \
-o recordsize=16K \
-o primarycache=metadata \
-o logbias=throughput \
-o mountpoint=/var/lib/pgsql \
tank/db
# WAL 日志:低延迟(如果用 SLOG)
# (在 pool 上加 log vdev)
# 备份
$ zfs create -o compression=zstd \
-o recordsize=1M \
-o mountpoint=/backup \
tank/backup
六、常见坑
1. compression 影响 zfs send/recv
压缩后数据传给未压缩 dataset 时,会自动重压缩。zfs send 会有 overhead。
2. encryption 不能事后加
# 创建时加密
$ zfs create -o encryption=aes-256-gcm ... tank/secure
# 已有 dataset 加加密?需要 zfs send/recv:
$ zfs send tank/data@before | zfs recv -o encryption=aes-256-gcm tank/data-secure
3. quota + snapshot 的陷阱
quota=10G + 频繁快照 → 用户主数据无法超过 10G(包括快照)。
用 refquota=10G 才能允许"主数据 10G + 任意多快照"。
4. reservation 的滥用
reservation 会"预占"空间,没有真正使用也会消耗 pool 容量。不要无脑给所有 dataset 配 reservation。
七、本篇小结
| | |
|---|
| zfs set compression=lz4 tank/data | |
| zfs create -o encryption=aes-256-gcm ... | |
| zfs set quota=10G tank/data | |
| zfs set refquota=10G tank/data | |
| zfs set reservation=10G tank/data | |
经验口诀:
- • 压缩:lz4 一把梭,冷数据
zstd-9 压 - • 配额:多用户用 refquota,别用 quota
- • 预占:重要业务 reservation,普通业务不加