使用 FreeBSD 11.1-STABLE,我有一个配置了 gzip-9 压缩的 ZFS 数据集,以及 8K 的记录大小。 (此卷用于小文件的归档,而不是速度。)
zfs get all pool02/redactedStorage
显示了 1.4 倍的压缩比,这比我预期的要差,但那里存储着文本文件和压缩文件的混合,所以并不令人担忧。然后我查看了该数据集中存储的一些大型 zip 文件,感到很困惑。
du -h
和的输出du -hA
不是我对压缩文件的期望。
例如,我预计 40 MB 的零文件几乎不会占用任何磁盘空间:
# dd if=/dev/zero of=testfile bs=4M count=10
# du -h testfile
512B testfile
# du -hA testfile
40M testfile
但我预计 40 MB 的随机文件会消耗约 40 MB 的磁盘空间,因为它是不可压缩的(出于所有实际目的)。但没想到消耗了将近双倍的空间:
# dd if=/dev/random of=testfile.rnd bs=4M count=10
# du -h testfile.rnd
92M testfile.rnd
# du -hA testfile.rnd
40M testfile.rnd
通过研究,它看起来像是间接块消耗了额外的空间。
对于testfile
(零):
Dataset pool02/redactedStorage [ZPL], ID 56, cr_txg 360697, 958G, 22881480 objects, rootbp DVA[0]=<0:9dd68959000:3000> DVA[1]=<0:14e1475b5000:3000> [L0 DMU objset] fletcher4 uncompressed LE contiguous unique double size=800L/800P birth=25863270L/25863270P fill=22881480 cksum=13497492df:14cc540c2b5f:e089aa02d6109:73afb0d244bcb42
Object lvl iblk dblk dsize lsize %full type
22910497 3 128K 8K 0 40.0M 0.00 ZFS plain file
168 bonus System attributes
dnode flags: USED_BYTES USERUSED_ACCOUNTED
dnode maxblkid: 5119
path /testfile
uid 0
gid 1004
atime Wed Apr 19 00:08:20 2023
mtime Wed Apr 19 00:08:20 2023
ctime Wed Apr 19 00:08:20 2023
crtime Wed Apr 19 00:08:20 2023
gen 25862395
mode 100644
size 41943040
parent 17938432
links 1
pflags 40800000004
Indirect blocks:
[ No Indirect blocks ]
对于testfile.rnd
(随机性):
Dataset pool02/redactedStorage [ZPL], ID 56, cr_txg 360697, 958G, 22881480 objects, rootbp DVA[0]=<0:9dbfec9d000:3000> DVA[1]=<0:14ffe1461000:3000> [L0 DMU objset] fletcher4 uncompressed LE contiguous unique double size=800L/800P birth=25863170L/25863170P fill=22881480 cksum=13b3f2c021:15912a82ff8a:ebef1e0641453:7abda3903292dba
Object lvl iblk dblk dsize lsize %full type
22910499 3 128K 8K 91.9M 40.0M 100.00 ZFS plain file
168 bonus System attributes
dnode flags: USED_BYTES USERUSED_ACCOUNTED
dnode maxblkid: 5119
path /testfile.rnd
uid 0
gid 1004
atime Wed Apr 19 00:16:47 2023
mtime Wed Apr 19 00:16:48 2023
ctime Wed Apr 19 00:16:48 2023
crtime Wed Apr 19 00:16:47 2023
gen 25862495
mode 100644
size 41943040
parent 17938432
links 1
pflags 40800000004
Indirect blocks:
[ 5120 Indirect blocks redacted ]
那么是不是 5120 个间接块 * 128K = 640M,然后这些块被压缩,导致 51.9M 的开销?
如果是这样,解决这个问题的最佳方法是什么? 创建一个具有更大记录大小的新数据集并将内容移过来?
这是我的数据集参数:
NAME PROPERTY VALUE SOURCE
pool02/redactedStorage type filesystem -
pool02/redactedStorage creation Mon Jan 28 1:03 2019 -
pool02/redactedStorage used 958G -
pool02/redactedStorage available 15.1T -
pool02/redactedStorage referenced 958G -
pool02/redactedStorage compressratio 1.40x -
pool02/redactedStorage mounted yes -
pool02/redactedStorage quota none local
pool02/redactedStorage reservation none local
pool02/redactedStorage recordsize 8K local
pool02/redactedStorage mountpoint /mnt/pool02/redactedStorage default
pool02/redactedStorage sharenfs off default
pool02/redactedStorage checksum on default
pool02/redactedStorage compression gzip-9 local
pool02/redactedStorage atime on default
pool02/redactedStorage devices on default
pool02/redactedStorage exec on default
pool02/redactedStorage setuid on default
pool02/redactedStorage readonly off default
pool02/redactedStorage jailed off default
pool02/redactedStorage snapdir hidden default
pool02/redactedStorage aclmode passthrough local
pool02/redactedStorage aclinherit passthrough inherited from pool02
pool02/redactedStorage canmount on default
pool02/redactedStorage xattr off temporary
pool02/redactedStorage copies 1 default
pool02/redactedStorage version 5 -
pool02/redactedStorage utf8only off -
pool02/redactedStorage normalization none -
pool02/redactedStorage casesensitivity sensitive -
pool02/redactedStorage vscan off default
pool02/redactedStorage nbmand off default
pool02/redactedStorage sharesmb off default
pool02/redactedStorage refquota none local
pool02/redactedStorage refreservation none local
pool02/redactedStorage primarycache all default
pool02/redactedStorage secondarycache all default
pool02/redactedStorage usedbysnapshots 0 -
pool02/redactedStorage usedbydataset 958G -
pool02/redactedStorage usedbychildren 0 -
pool02/redactedStorage usedbyrefreservation 0 -
pool02/redactedStorage logbias latency default
pool02/redactedStorage dedup off inherited from pool02
pool02/redactedStorage mlslabel -
pool02/redactedStorage sync standard default
pool02/redactedStorage refcompressratio 1.40x -
pool02/redactedStorage written 958G -
pool02/redactedStorage logicalused 501G -
pool02/redactedStorage logicalreferenced 501G -
pool02/redactedStorage volmode default default
pool02/redactedStorage filesystem_limit none default
pool02/redactedStorage snapshot_limit none default
pool02/redactedStorage filesystem_count none default
pool02/redactedStorage snapshot_count none default
pool02/redactedStorage redundant_metadata all default
zdb
以及显示相关池的部分输出:
(注意ashift: 12
此池的底层 vdev。)
pool02:
version: 5000
name: 'pool02'
state: 0
txg: 25383030
pool_guid: 1288056053628670413
hostid: 3785389258
hostname: 'redacted'
com.delphix:has_per_vdev_zaps
vdev_children: 1
vdev_tree:
type: 'root'
id: 0
guid: 1288056053628670413
create_txg: 4
children[0]:
type: 'raidz'
id: 0
guid: 9072182531784548301
nparity: 2
metaslab_array: 49
metaslab_shift: 37
ashift: 12
asize: 23978959699968
is_log: 0
create_txg: 4
com.delphix:vdev_zap_top: 36
children[0]:
type: 'disk'
id: 0
guid: 17108175667375824896
path: '/dev/gptid/e07bacd6-1224-11e9-98bd-90b11c29519f'
whole_disk: 1
DTL: 293
create_txg: 4
com.delphix:vdev_zap_leaf: 37
children[1]:
type: 'disk'
id: 1
guid: 6726950469173540573
path: '/dev/gptid/e443f9f2-1224-11e9-98bd-90b11c29519f'
whole_disk: 1
DTL: 292
create_txg: 4
com.delphix:vdev_zap_leaf: 38
--------==== 10 ADDITIONAL PHY DISKS REDACTED ====---------
features_for_read:
com.delphix:hole_birth
com.delphix:embedded_data
答案1
在由 12 个具有 4K 扇区(共 12 个)的磁盘组成的 vdev 上条带化 8K 记录ashift
是一个糟糕的主意,并且会导致大量的开销:
来自 OpenZFS:
https://openzfs.github.io/openzfs-docs/基本概念/RAIDZ.html
由于这些输入,如果记录大小小于或等于扇区大小,则 RAIDZ 的奇偶校验大小将有效地等于具有相同冗余的镜像。例如,对于 3 个磁盘的 raidz1,ashift=12 且recordsize=4K,我们将在磁盘上分配:
1个4K数据块
1 个 4K 填充块
可用空间率为50%,与双镜相同。
另一个示例,对于 3 个磁盘的 raidz1,ashift=12 且记录大小=128K:
总条纹宽度为 3
由于有 1 个奇偶校验块,一个条带最多可以有 2 个 4K 大小的数据部分
我们将有 128K/2 = 64 个条带,每个条带有 8K 数据和 4K 奇偶校验
因此本例中的可用空间率为 66%。
RAIDZ的磁盘越多,条带越宽,空间效率就越高。
该文本后面是一个图表,如果截屏并内嵌在此处,该图表将难以辨认,但它显示,对于 1 倍或 2 倍扇区大小的记录大小,在 RAIDZ2 下,开销将为 67%。
根据图表,这种情况下的解决方案是增加到recordsize
256K,这在 12 磁盘 RAIDZ2 vdev 上的奇偶校验+填充成本为 18%。 (recordsize
相比之下,128K会产生 24% 的开销)。
但事情没那么简单。对于“经典”文件系统来说,最初选择 8Krecordsize
可能是正确的,就像recordsize
最大限度块大小,不是固定的块大小。然而,对于较大recordsize
且相对较小的文件仍然存在惩罚。
增加recordsize
只会影响更改后创建的数据,但在这种情况下,池仅消耗 6% 的空间,当前压缩率为 1.4 倍。现有数据可以保留在原位,而不会造成任何长期容量问题。然而,在需要回收开销的情况下:
https://openzfs.github.io/openzfs-docs/性能和调优/工作负载调优.html
如果您更改记录大小,因为您的应用程序应该使用不同的记录大小来执行更好的操作,则您将需要重新创建其文件。每个文件上的 cp 后跟 mv 就足够了。或者,当完整接收完成时,send/recv 应重新创建具有正确记录大小的文件。
来自对相关池的真实实验:
# zfs set recordsize=256K pool02/redactedStorage
# dd if=/dev/zero of=testfile256.40M.zeroes bs=1M count=40
# du -h testfile256.40M.zeroes
512B testfile256.40M.zeroes
# dd if=/dev/random of=testfile256.40M.rnd bs=1M count=40
# du -h testfile256.40M.rnd
40M testfile256.40M.rnd
# dd if=/dev/random of=testfile256.8K.rnd bs=8192 count=1
# du -h testfile256.8K.rnd
37K testfile256.8K.rnd
如您所见,40M 文件正在使用逻辑空间量。但是一个8K的文件就消耗了37K的空间!
因此recordsize
应该根据数据集的内容进行调整。
当然,看起来128K默认值recordsize
是最佳的,我只是不应该碰它。
# zfs set recordsize=128K pool02/redactedStorage
# cp testfile256.40M.rnd testfile128.40M.rnd
# du -h testfile128.40M.rnd
512B testfile128.40M.rnd
# mv testfile128.40M.rnd testfile128.40M.rnd2
# du -h testfile128.40M.rnd2
40M testfile128.40M.rnd2
# cp testfile256.8K.rnd testfile128.8K.rnd
# mv testfile128.8K.rnd testfile128.8K.rnd2
# du -h testfile128.8K.rnd2
19K testfile128.8K.rnd2
这确实显示 8K 测试文件使用 19K 磁盘空间,但是存在必要的元数据开销。看着不可压缩现有文件大小 <=8K,所有文件在原始文件下recordsize=8K
也显示 19K 的磁盘使用量。我进一步尝试recordsize=64K
,它对这些示例文件的大小没有影响。
另请注意,cp
后面的mv
确实是在 new 下创建文件实例所必需的recordsize
。
这篇文章还对正在发生的事情进行了很好的描述,我将把这些描述供后代使用:
https://klarasystems.com/articles/choosing-the-right-zfs-pool-layout/
- 填充、磁盘扇区大小和记录大小设置:在 RAID-Z 中,奇偶校验信息与每个块相关联,而不是像 RAID-5 中那样与特定条带相关联,因此每个数据分配必须是 p+1(奇偶校验+1)的倍数,以避免释放的段太小被重复使用。如果分配的数据不是 p+1 的倍数,则使用“填充”,这就是 RAID-Z 需要比 RAID-5 多一点的奇偶校验和填充空间的原因。这是一个复杂的问题,但简而言之:为了避免空间效率低下,您必须保持 ZFS 记录大小远大于磁盘扇区大小;您可以对 512 字节扇区磁盘使用 Recordsize=4K 或 8K,但如果您使用 4K 扇区磁盘,则 Recordsize 应是该值的几倍(默认 128K 即可),否则最终可能会丢失太多空间。