ZFS提供了提高磁盘空间利用率的方法。
ZFS可以在文件系统级别使用压缩。
ZFS可以牺牲内存为代价执行去重操作,以提高磁盘使用率。
df命令显示每个分区上的可用空间量;du命令显示分区或目录树中使用了多少磁盘。
这两个命令很适合传统的文件系统,但不太适合ZFS。
例如:
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
zroot 17.5G 874G 144K none
zroot/ROOT 1.35G 874G 144K none
zroot/ROOT/default 1.35G 874G 1.35G /
zroot/usr 12.5G 874G 454M /usr
zroot/usr/local 1.84G 874G 1.84G /usr/local
...
根据此数据,zroot池使用了17.5GB空间。数据集zroot/ROOT使用1.35GB数据。数据集zroot/ROOT/default也使用了1.35GB。然而zroot/ROOT/default包含在zroot/ROOT中。所有这1.35GB数据是相同的。
同样,zroot/usr使用的12.5GB也包括它下面的所有内容。
使用ZFS,不能只加上已使用的空间量来获得总数。
AVAIL列(或叫 sapce available)显示的数据更可靠。zroot池拥有847GB可用空间。
一旦是开始使用快照和克隆以及其他ZFS优点,由于引用了数据,这个847GB的空间可以包含数倍于此的数据。
数据集中包含的数据量是引用的数据。查看上例中的REFER列。zroot池和zroot/ROOT都引用了144KB的空间(144KB空间一般是占位符(placeholder)所占空间)。数据集zroot/ROOT/default引用了1.35GB的数据。
引用的数据是存在于这个文件系统或数据集中的东西。如果进入zroot/ROOT/default文件系统,会发现1.35GB的内容。
多个ZFS数据集可以引用同一组数据,这正是快照和克隆的工作原理,这就是为什么ZFS可以在11GB的空间中保存几个10GB的快照。所以引用空间加起来并不等于使用的量。
克隆使用空间的方式于快照非常相似,只是更具有动态性。一旦添加了去重和压缩,磁盘空间的使用就会变得非常复杂。
甚至还有关于释放空间的问题。
在许多ZFS部署中,删除文件实际上并没有释放空间。大多数情况下,由于快照和元数据,删除实际上会使磁盘空间使用量略有增加。
这些文件使用的空间将分配给最新的快照。
要成功管理ZFS,必须了解底层功能是如何工作的,以及ZFS在删除数据时的作用。
在使用快照和克隆的文件系统上,新释放的空间不会立即出现。许多ZFS操作异步释放空间,因为ZFS会更新引用该空间的所有块。
池的freeing属性显示了ZFS仍需要从池中回收多少空间。如果一次性释放一大堆空间,可以看到freeing属性的减少,自由空间增加。
ZFS回收空间的速度取决于硬件、负载量、池设计、碎片级别以及空间的使用方式。
异步释放空间容易理解:可以查看freeing属性,看看它下降的速度有多快。
但对于新手来说,ZFS的磁盘使用似乎要奇怪很多。
要查看磁盘空间的确切位置,使用zfs list -o space:
xxxxxxxxxx
# zfs list -o space
NAME AVAIL USED USEDSNAP USEDDS USEDREFRESERV USEDCHILD
zroot 874G 17.5G 0 144K 0 17.5G
zroot/ROOT 874G 1.35G 0 144K 0 1.35G
zroot/ROOT/default 874G 1.35G 0 1.35G 0 0
zroot/usr 874G 12.5G 0 454M 0 12.0G
...
此例中zroot/usr数据集使用了12.5GB,引用454MB,而其子数据集占用了12GB。
想要查阅磁盘使用情况,应使用zfs list -o space命令。也可使用类似以下命令查看指定数据集及其子数据集的使用情况:
xxxxxxxxxx
# zfs list -r -o space zdata/film
zfs list的-o选项后面可以跟若干属性名称,各属性之间用逗号隔开。
例如:
xxxxxxxxxx
# zfs list -o name,creation,available -r zdata/film
NAME CREATION AVAIL
zdata/film Tue Jun 4 14:23 2024 3.97T
zdata/film/4k Tue Jun 4 14:23 2024 3.97T
zdata/film/documentary Wed Jun 5 7:56 2024 3.97T
zdata/film/movies Wed Jun 5 10:38 2024 3.97T
zdata/film/mp3 Thu Jun 6 8:09 2024 3.97T
zdata/film/mv Thu Jun 6 9:55 2024 3.97T
有时池的可用空间比数据集的空间使用情况更重要。
对于镜像池或条带池,池空间信息相当接近现实。但对于冗余的RAID-Zn系统,理论上可以根据属性、池的当前使用情况和一些计算方式来猜测空间的使用量。但更简单的方法是向zfs询问池的根数据集。
xxxxxxxxxx
# zfs list zroot
NAME USED AVAIL REFER MOUNTPOINT
zroot 37.7G 854G 144K none
此池使用了37.7GB,剩余854GB空间。
ZFS有各种奇特的能力对其磁盘使用情况的显示进行切片(slice)和切块(dice)。
在ZFS环境下,df命令显示的结果往往是错误的。
传统的文件系统由单个分区组成,该分区的大小取决于底层磁盘上分配的块数。df工具迭代每个已挂载的文件系统,并显示分区的大小、当前使用的空间量以及剩余的可用空间量。
遍历文件系统对ZFS不起作用,因为数据集不是文件系统。默认情况下数据集没有设置配额,所以它没有最大大小。
为了提供一些与传统df工具的兼容性,ZFS提供了一个善意的谎言。由于ZFS数据集在传统文件系统意义上没有“size”,因此它将已使用的空间和整个池的可用空间加在一起,并将该值表示为数据集的size。
上一节中的示例里,zroot/ROOT/default数据集使用了1.35GB空间,还剩余874GB可用空间,总大小为875.35GB。然后,查看zroot/usr数据集,它使用了12.5GB,剩余847GB,总共886.5GB。
现在,用df命令查看这些数据集:
xxxxxxxxxx
# df -h
Filesystem Size Used Avail Capacity Mounted on
zroot/ROOT/default 875G 1.4G 874G 0% /
zroot/usr 874G 454M 874G 0% /usr
...
/文件系统是875GB,/usr是874GB,这两个加起来就有1749GB,还剩余1748GB。
而实际上整个磁盘仅有1TB,以上所显示的文件系统使用百分比的Capacity列同样是伪造的。
随着数据集的增大,可用空间的数量会减少。根据df,文件系统随着空间的使用而缩小,当空间被释放时则会增长。
需要特别注意,类似df的传统文件系统工具会给出不正确的答案。监控ZFS系统需要ZFS专用工具。
当与用于传统文件系统的其他工具一起查看时,这种行为会产生有趣的副作用。
通过Samba在Windows计算机上挂载ZFS数据集,将仅显示已使用的极小空间量,池中剩余的空间量为可用空间。随着池中充满数据,Windows会看到驱动器缩小。
使用ZFS时,应养成用精确工具管理它的习惯。
ZFS的灵活性意味着用户和应用程序可以使用可用的磁盘空间。但这有利有弊。比如/var/log的无限制增长可能会填满磁盘。或者某些用户在他的目录中存放了过多的文件,造成主数据库空间不足。
配额(quota)和预留(reservation)可以防止这些问题。
配额规定了数据集及其所有子集可以使用的最大空间量。如果将挂载为/home的数据集设置为100GB的配额,/home及其下的所有数据集和快照使用的总空间量都不能超过100GB。
预留则决定了为数据集留出的空间量。为了确保数据库始终有空间写入文件,应使用预留为该数据集腾出一定量的磁盘空间。
以下先讨论预留,再讨论限额。
预留会为数据集及其子数据集留出一块磁盘空间。系统将不允许其他数据集使用该空间。
即使池空间不足,预留的空间仍将可用于写入该数据集。
假设我们从1TB的池中为/var/db预留100GB,我们的数据库将其数据文件存储在/var/db中。这个数据集中有大约50GB的数据,
一个日志文件发了疯,填满了池的其余部分。我们会收到系统上其他程序的错误,说磁盘已满,但数据库程序在/var/db中仍有可用的空间。它可能会抱怨无法将程序日志写入/var/log/db,但这是一个单独的问题。
ZFS使用两个ZFS属性管理预留:refreservation和reservation。
refreservation会影响数据集的引用数据(referenced data),也就是说,它不包括快照、克隆和其他后代。
reservation则包括子数据集、快照等。
例如:
xxxxxxxxxx
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
zroot/usr 12.5G 874G 454M /usr
zroot/usr/local 1.84G 874G 1.84G /usr/local
zroot/usr/obj 6.89G 874G 6.89G /usr/obj
zroot/usr/ports 1.97G 874G 816M /usr/ports
…
zroot/usr数据集挂载到/usr。它使用了12.5GB,包括子数据集(比如/usr/local,/usr/obj等)。它仅引用了454MB,这意味着主数据集zroot/usr上的数量不到半GB。
如果在zroot/usr上设置了1GB的reservation,那基本上时没有意义的。子数据集的现有文件远远超出了预留值。
如果在zroot/usr上设置1G的refreservation,它只会影响zroot/usr上的文件。子数据集被排除在外。此时数据集处于半满状态,因此还有空间可以写入更多文件。
这是一个极端的例子。假设想确保所有用户都获得至少1GB的空间,为每个用户的主目录创建一个单独的数据集,并为每个用户分配一个预留值(reservation)。
reservation可以嵌套。假设有两个数据集,zroot/var/log和zroot/var/log/db,后者专门用于数据库服务器。希望数据库服务器日志始终至少有10GB的空间,因此为zroot/var/log/db分配了一个reservation。然后,需要20GB的通用服务器日志,如果希望这20GB包括数据库的日志,可使用reservation设置zroot/var/log;而如果希望这20GB的保留不包括数据库日志,则应使用refreservation设置zroot/var/log。
数据集可能同时具有reservation和refreservation。
数据集zroot/var/log/db为当前日志文件保留了10GB的refreservation空间,但应该设置更大的reservation空间,以便可以对数据集进行快照并单独计算其使用情况。
试图违反reservation会产生“空间不足”错误。当出现该错误时,即使仍有可用磁盘空间,也应该检查reservation设置。保留的数据集将显示可用空间,但所有其他数据集可能都满了。
使用zfs get reservation,refreservation,usedbyrefreservation来查看特定的属性列表:
xxxxxxxxxx
# zfs get reservation,refreservation,usedbyrefreservation zroot/var/log
NAME PROPERTY VALUE SOURCE
zroot/var/log reservation none default
zroot/var/log refreservation none default
zroot/var/log usedbyrefreservation 0B -
或者使用偷懒的方法——使用grep过滤信息:
xxxxxxxxxx
# zfs get all zroot/var/log/db | grep reserv
zroot/var/log/db reservation none default
zroot/var/log/db refreservation none default
zroot/var/log/db usedbyrefreservation 0 -
可以使用zfs list -o name,reservation,refreservation,usedbyrefreservation查看对应的信息:
xxxxxxxxxx
# zfs list -o name,reservation,refreservation,usedbyrefreservation zroot/var/log
NAME RESERV REFRESERV USEDREFRESERV
zroot/var/log none none 0B
usedbyrefreservation属性显示了如果删除refreservation,此数据集将释放多少空间。
设置预留与设置其他ZFS属性一样:
xxxxxxxxxx
# zfs set refreservation=10G zroot/var/log/db
# zfs set reservation=20G zroot/var/log
取消预留设置的方法是将对应的属性值设置为none:
xxxxxxxxxx
# zfs set reservation=none zroot/var/log
quota表示数据集、用户、用户组可以使用的最大空间量。
所有配额都是基于每个数据集设置的。
类似于预留,配额也使用了两个属性:quota和refquota。
如果不想配额影响快照和子数据集,应设置refquota属性。
使用zfs set quota设置配额:
xxxxxxxxxx
# zfs set quota=100G zroot/var/log
日志文件可以使用不超过100GB的空间,包括快照、子数据集和其他任何数据。
xxxxxxxxxx
# zfs set refquota=50G zroot/var/log
# zfs set refquota=50G zroot/var/log/db
# zfs set quota=500G zroot/var/log
以上示例中,我们为两个日志数据集设置了单独的refquota,并为这两个数据一起设置了quota。
使用以下命令可以查看数据集的配额:
xxxxxxxxxx
# zfs get all zroot/home | grep quota
zroot/home quota none default
zroot/home refquota none default
配额会改变数据集的最大大小和数据集的可用空间。此池有数百GB的可用空间,但对此数据集执行zfs list却显示情况并非如此:
xxxxxxxxxx
# zfs list zroot/var/log
NAME USED AVAIL REFER MOUNTPOINT
zroot/var/log 25.0G 75.0G 5.01G /var/log
zroot/var/log数据集有25GB数据,75GB可用空间。ZFS知道有100GB的配额,它显示了正确的使用率。这比df显示的要准确。
xxxxxxxxxx
# zfs list zroot/var/log/db
NAME USED AVAIL REFER MOUNTPOINT
zroot/var/log/db 20.0G 85.0G 10.0G /var/log/db
ZFS知道父数据集的配额是100GB,因此也在子数据集上设置了最大的大小。
如果/var/log有75GB可用空间,/var/log/db有85GB可用空间,是不是意味着这两个分区有160GB的可用空间?不是,因为池的可用空间是这两个分区共用的。
数据集zroot/var/log/db似乎有更多的可用空间,因为其父数据集中的数据没有反映在子数据中的使用情况中。
如果用户或进程试图编写一些会超出数据集配额的内容,会收到配额错误:
xxxxxxxxxx
# cp script.sh testscript.sh
cp: testscript.sh: Disc quota exceeded
需要释放一些空间,但要注意,快照可能会使这一过程复杂化。
如果同时设置了quota和refquota,则用户可能能够通过删除文件来释放空间,即使这回增加文件系统快照的大小。
用户和组配额控制用户或组可以向数据集写入多少数据。
与数据集配额一样,用户和组配额是基于每个数据集进行控制的。
用户和组配额不适用于子文件系统、快照和克隆。必须将配额应用于希望它们影响的每个单独的数据集。
使用zfs userspace命令可以查看数据集中每个用户使用了多少空间。
xxxxxxxxxx
# zfs userspace zroot/home
TYPE NAME USED QUOTA
POSIX User 179 7.29M none
POSIX User mwlucas 1.16G none
POSIX User root 298M none
此例中,用户mwlucas使用了1.16GB。用户root使用了298MB。
当使用tar -p提取tarball时,会保留原始文件的所有权,这可能会带来本系统没有的用户ID。
在FreeBSD14.1系统上,以上命令的输出结果中还有OBJUSED和OBJQUOTA列,从列的名称看,应该是列出了userobjused和userobjquota属性值。
使用zfs groupspace命令显示每个组所拥有的文件使用了多少空间:
xxxxxxxxxx
# zfs groupspace zroot/usr/local
TYPE NAME USED QUOTA
POSIX Group _tss 25.5K none
POSIX Group bin 93.5K none
POSIX Group kmem 128K none
POSIX Group messagebus 392K none
POSIX Group polkit 115K none
POSIX Group wheel 1.85G none
如果服务器有多个组,可以为每个组或用户设置配额。
使用userquota和groupquota属性设置用户和组的配额。在属性名称后面添加@符号来指定用户或组的名称。例如:
xxxxxxxxxx
# zfs set userquota@mwlucas=1G zroot/home
上一节显示,mwlucas账户中有超过1G的数据,已经超出了配额,当用户尝试创建文件时,会收到错误提示:
xxxxxxxxxx
$ touch test
touch: test: Disc quota exceeded
同样,使用groupquota@设置组配额:
xxxxxxxxxx
# zfs set groupquota@staff=10G zroot/home
要清除配额,可以将配额值设置为none。
使用以下命令查看用户或组的配额:
xxxxxxxxxx
# zfs get userquota@mwlucas zroot/tmp
NAME PROPERTY VALUE SOURCE
zroot/tmp userquota@mwlucas 10M local
如果不能增加现有磁盘的大小,可以更改数据使用磁盘的方式。
ZFS可以在文件系统级别实现实时压缩文件。包括专门为文件系统使用而设计的压缩算法。
压缩和解压缩需要消耗CPU的时间,因此盲目地在任何地方启用最严格的gzip压缩可能会对磁盘性能增加另一个限制。
ZFS压缩在每个数据集的基础上工作,可以指定某些数据集启用压缩,而其他数据集不启用。
使用compression属性启用和禁用压缩。现在我们先查看压缩设置:
xxxxxxxxxx
# zfs get compress zroot/usr
NAME PROPERTY VALUE SOURCE
zroot/usr compression off default
默认的压缩算法是LZJB(FreeBSD14.1版默认是LZ4),并不是ZFS提供的最有效的算法。几乎所有情况下都使用LZ4压缩。
下面例子中我们指定zroot池中所有数据集使用LZ4压缩,但是特别指定zroot/var/cdr数据集使用gzip-9压缩算法:
xxxxxxxxxx
# zfs set compress=lz4 zroot
# zfs set compress=gzip-9 zroot/var/cdr
ZFS在文件写入磁盘时压缩文件。如果你有一个充满文本文件的数据集,添加压缩不会使它们缩小。为了减少文件使用的磁盘空间,您必须在启用压缩后重写所有文件。
LZ4是一种更新、更快的特定文件系统压缩算法。并非所有数据都是可压缩的,LZ4可以快速检测不可压缩的文件,并且不会尝试压缩它们。如果没有特殊需求,应使用LZ4压缩算法。
ZLE算法压缩文件中的零字符串。这是一个最小的压缩系统,对大多数文件来说不是很有用。
对于特殊情况,ZFS支持gzip压缩。gzip比LZ4使用更多的CPU时间,但对于某些数据集来说可能更有效。对于不经常访问的数据,节省磁盘空间可能更重要。
gzip有九个压缩级别,从1(最快但压缩比最小)到9(最慢但压缩比最大)。
xxxxxxxxxx
# zfs set compress=gzip-1 zroot/var/log
指定gzip但没有指定级别的话,ZFS默认使用级别6。
有几个属性可以深入了解ZFS压缩数据的效果。
如何判断数据是否可以从压缩中受益,或者不同的算法如何影响文件大小?
获取一些典型的数据文件并对其进行测试。使用du或ls -ls查看磁盘上文件的实际大小。
在测试自己的数据时,需要使用一大堆不同的实际数据文件。
以下示例中的文件来自古腾堡计划中的人类基因组计划。
xxxxxxxxxx
# du hgp.txt
280721 hgp.txt
未压缩的情况下,这个文件占用280721个块,或者大约274MB。
用于测试的数据集叫db。这个数据集上还没有其他数据,因此我们可以准确地评估压缩对这个特定文件地影响。现在,启用压缩:
xxxxxxxxxx
# zfs set compression=on db
再查看文件大小:
xxxxxxxxxx
# du hgp.txt
280721 hgp.txt
文件大小没有变化,因为压缩、去重等类似功能仅适用于已经启用了该功能后写入的文件。删除文件并重新放入:
xxxxxxxxxx
# rm /db/*
# cp /home/mwl/hgp.txt /db
等几秒钟让ZFS完成写入动作,再次查看:
xxxxxxxxxx
# du /db/hgp.txt
139577 /db/hgp.txt
文件仅使用了139577个块,大约136MB。大约缩小了一半,像数据集属性显示的那样:
xxxxxxxxxx
# zfs get compressratio,refcompressratio db
NAME PROPERTY VALUE SOURCE
db compressratio 2.01x -
db refcompressratio 2.01x -
refcompressration和compressratio属性值相同,因为数据集中只有一块数据,而且池上也只有一个数据集。在复杂的池中,值可能会不同。
试试修改压缩算法为lz4:
xxxxxxxxxx
# zfs set compression=lz4 db
重新复制文件,等几秒钟,再次查看:
xxxxxxxxxx
# du /db/hgp.txt
146076 /db/hgp.txt
LZ4将数据压缩到142MB,在这个特定文件上,LZ4如不LZJB有效。这是因为不同的算法对不同的数据有不同的处理方式。
再试试gzip:
xxxxxxxxxx
# zfs set compress=gzip-1 db/text
重新复制文件,再次查看:
xxxxxxxxxx
# du /db/hgp.txt
74104 /db/hgp.txt
这次数据只有72MB了,压缩比(compressratio)达到了3.78。调高gzip级别:
xxxxxxxxxx
# zfs set compress=gzip-9 db/text
# cp /home/mwl/hgp.txt /db/
# du /db/hgp.txt
63614 /db/hgp.txt
使用gzip-9压缩的数据仅剩下了62MB,压缩比达到了4.41。gzip-9使可用空间增加了四倍多。
但以上示例是骗人的,除了古腾堡计划添加的样板外,人类基因组计划完全由四个字母组成。它可能是现存最冗余、最可压缩的真实世界数据。从大多数现实世界的数据中,你不能指望这一点。
通常,除非在有迫切需要时才更改LZ4的压缩算法,额外的CPU开销和较慢的磁盘访问不会影响LZ4算法的实际工作。
只有按照上一节测试后能获取更大压缩比时,才考虑更换压缩算法。
先看一下示例中的这些属性:
xxxxxxxxxx
# zfs get all db | grep reference
db/text referenced 48.7M -
db/text logicalreferenced 220M -
这个数据集用了48.7MB磁盘空间。如果忽略压缩,数据集有220MB的数据。压缩的数据集可以存储更多的逻辑数据。
这就是压缩的有效性真正发挥作用的地方。读写数据最慢的部分是在存储介质上获取数据。
物理介质是磁盘事务中最慢的部分。将48.7 MB写入磁盘所需的时间大约是写入220 MB的22%。
通过启用压缩,您可以以少量CPU时间为代价将存储时间缩短78%。
如果您的磁盘可以写入100 MB/s,那么写入48.7 MB的压缩数据大约需要半秒。
如果你从写数据的应用程序的角度来看,你实际上在半秒内写了220 MB,相当于440 MB/s。我们打赌你不认为你的笔记本电脑磁盘可以做到这一点!
如果你存储了许多小文件,压缩的效果就不那么好。小于扇区大小的文件无论如何都会被分配一个完整的块。如果你想要真正有效的压缩,请使用具有实际512字节物理扇区的磁盘,并告诉ZFS使用该扇区大小。
压缩并不完美。顺序和随机访问可以改变压缩的性能。始终在您的环境中使用您自己的数据进行测试。压缩工作得很好,FreeBSD在默认安装中启用了lz4压缩。
大多数CPU大多处于空闲状态。让懒惰的动物处理一些数据!
要停用压缩,应将数据集的compression属性设置为off。
就像激活压缩只会影响新写入的文件一样,停用压缩只影响新数据。压缩文件在重写之前保持压缩状态。ZFS足够聪明,可以知道文件是压缩的,并在访问时自动解压缩,但它仍然有开销。
除非重写所有文件,否则无法清除数据集中的所有压缩痕迹。你最好重新创建数据集。
文件一遍又一遍地重复相同的数据,排列方式略有不同。多个文件包含更多的重复。您系统中超过一半的数据可能是其他地方发现的数据的重复。ZFS可以识别文件中的重复数据,提取并记录它,从而只存储每条数据一次。这与压缩非常相似。在某些情况下,去重可以减少磁盘使用。
ZFS在文件系统块级别进行去重(由reconrdsize属性显示)。
使用较小的块可以提高去重的效果,但会增加内存需求。ZFS仅存储一次相同的块,并将去重表存储在内存中。
为了实现高效的去重,系统必须有足够的内存来保存整个去重表。
ZFS将去重表存储在磁盘上,但如果主机每次想要访问文件时都必须查阅磁盘上的副本,性能将变慢。
慎用。
经验而言,可以按每TB去重需要5GB的内存。
建议计算数据需要多少RAM,然后使用最悲观的结果。
去重后的数据集上的每个文件系统块使用大约320字节的RAM。ZFS的zdb工具可以分析一个池,看看有多少块被使用,使用-b选项:
x# zdb -b data
Traversing all blocks to verify nothing leaked ...
loading space map for vdev 1 of 2, metaslab 33 of 174 ...
5.45G completed ( 341MB/s) estimated time remaining: 0hr 00min 30sec
...
bp count: 139025
ganged count: 0
bp logical:18083569152 avg: 130074
bp physical: 18070658560 avg: 129981 compression: 1.00
bp allocated: 18076997120 avg: 130026 compression: 1.00
bp deduped: 0 ref>1: 0 deduplication: 1.00
SPA allocated: 18076997120 used: 1.81%
additional, non-pointer bps of type 0: 21
Dittoed blocks on same vdev: 1183
注:10T左右的池,以上操作可能需要1小时左右。
"bp count"显示了存储在池中的ZFS块大小的总数。这个池使用了139025个块。
如果池中有许多小文件,则需要更多的内存。
倒数第三行的used显示该池使用1.81%。假设此池中的数据在增长过程中将保持相当一致。将已使用的块数量四舍五入到140000。将使用的块除以块的满度,可以看到满池将有大约7734806个块,每个块320字节,这些数据使用2475138121字节的RAM,大约2.3GB。
这还不到经验法则的一半。假设此池上的ZFS重复数据删除表每TB存储需要5 GB RAM。
每TB的去重意味着至少20GB的RAM,即使根据块使用情况进行更有希望的计算,每TB磁盘需要2.3GB的RAM,25%的限制意味着每TB的去重池大约需要10GB的RAM。
ZFS可以模拟去重,并很好地估计数据的去重效果。在池上运行zdb -S,会得到一个很好的利用率和常见元素的直方图。最后一行的结果可用来参考:
xxxxxxxxxx
# zdb -S data
Simulated DDT histogram:
...
dedup = 3.68, compress = 1.00, copies = 1.00, dedup * compress / copies = 3.68
以上显示这个池数据可以重复3.68次,如果这个池中的所有数据都是可以去重的,那么可以在每TB的存储中容纳3.68TB的数据。然而这些数据可能存在异常冗余,用户程序和主目录的zroot池大约是1.06可去重。
根据实际情况,更快的磁盘和更多的CPU来增强压缩比,比用大量内存进行去重,更具有成本效益。
去重并不能提高磁盘读取速度,尽管它可以提高缓存命中率。它只会在发现重复块时提高写入速度。
去重还会显著增加释放块所需的时间,因此销毁数据集和快照可能会变得非常缓慢。
去重可能只有在磁盘空间有限、价格昂贵且性能非常高的情况下才有意义。例如在SSD池中,去重才会显得有意义。
ZFS的dedup属性值(on或off)控制去重:
xxxxxxxxxx
# zfs set dedup=on data/data1
与压缩属性一样,去重属性仅影响新写入的数据。
将dedup设置为off可以关闭去重:
xxxxxxxxxx
# zfs set dedup=off data/data1
如果池中有去重的数据,关闭此属性并不会影响已经去重的数据,依然会继续因去重影响系统的性能。最好使用zfs send和zfs receive将数据发送到不使用去重的新数据集,才能完全消除影响。
最好的选择可能是不使用去重。