由于快照、克隆、保留、ZVOL和引用数据,ZFS可以轻松回答“此池有多少可用磁盘?”这样的问题,“什么正在使用我的所有空间?”这一问题更难回答。当尝试在ZFS数据集上使用传统的文件系统管理方法时,这些功能也可能会导致问题。您可能会发现没有足够的空间来删除文件,这非常令人困惑,直到您了解发生了什么。
ZFS提供了提高磁盘空间利用率的方法。ZFS可以在文件系统级别使用压缩,而不是要求系统管理员压缩单个文件。ZFS还可以执行文件的重复数据消除,以内存为代价大大提高了磁盘使用率。我们将看到如何评估这些选项,并确定何时使用每个选项。
但让我们从考虑ZFS的磁盘空间使用情况开始。
第六章:磁盘空间管理读取ZFS磁盘使用情况引用数据(referenced data)释放空间(freeing space)磁盘空间细节池空间使用ZFS, df(1), 和第三方工具限制数据集尺寸预留(reservation)查看预留设置和删除预留配额数据集配额设置配额查看配额超出配额用户和组配额查看每个数据集的已用空间和现有配额分配和删除用户和组的配额查看个人配额ZFS 压缩启用压缩压缩算法压缩属性选择算法何时更改压缩算法压缩和性能停用压缩去重去重内存需求去重效率启用去重禁用去重
df(1) 命令显示每个分区上的可用空间量;du(1) 命令显示分区或目录树中使用了多少磁盘。几十年来,系统管理员使用这些工具来查看是什么占用了他们的可用空间。它们非常适合于传统文件系统。然而,ZFS需要不同的思维方式。
考虑一下这个ZFS数据集(经过大量修剪)列表。
# zfs listNAME USED AVAIL REFER MOUNTPOINTzroot 17.5G 874G 144K nonezroot/ROOT 1.35G 874G 144K nonezroot/ROOT/default 1.35G 874G 1.35G /zroot/usr 12.5G 874G 454M /usrzroot/usr/local 1.84G 874G 1.84G /usr/local...根据这一点,zroot 池有17.5 GB正在使用中。乍一看,您可能认为 zroot/ROOT 和 zroot/ROOT/default 都使用1.35GB。你错了。
根据此数据,zroot池使用了17.5GB空间。数据集zroot/ROOT使用1.35GB数据。数据集zroot/ROOT/default也使用了1.35GB。然而zroot/ROOT/default包含在zroot/ROOT中。所有这1.35GB数据是相同的。
数据集 zroot/ROOT 使用1.35 GB的数据。该数据集中有1.35 GB的数据。数据集 zroot/ROOT/default 也使用1.35 GB的数据。然而,zroot/ROOT/default 数据集包含在 zroot/ROOT 数据集中。它是相同的1.35 GB数据。
类似地,考虑 zroot/usr 使用的12.5GB。该数据集具有子数据集,如 zroot/usr/local 、 zroot/usr/obj 等。这些数据集中的每个都使用一个数据块,通常为几GB。zroot/usr 使用的12.5GB包括其下的所有内容。
使用ZFS,您不能只将使用的空间量相加就得到总数。
AVAIL 列或可用空间在某种程度上更可靠。池 zroot 有874 GB的空白空间。一旦您开始使用快照和克隆以及所有其他ZFS优点,您就会发现由于引用的(referenced)数据,这874GB的空间可以包含比这多得多的数据。
数据集中包含的数据量是引用的数据。查看上例中的 REFER 列。zroot 池和 zroot/ROOT 都引用了144KB的空间(144KB空间一般是占位符(placeholder)所占空间)。数据集 zroot/ROOT/default 引用了1.35GB的数据。
引用的数据是存在于这个文件系统或数据集中的东西。如果进入 zroot/ROOT/default 文件系统,会发现1.35GB的内容。
多个ZFS数据集可以引用同一组数据,这正是快照和克隆的工作原理,这就是为什么ZFS可以在11GB的空间中保存几个10GB的快照。所以引用空间加起来并不等于使用的量。
克隆使用空间的方式于快照非常相似,只是更具有动态性。一旦添加了去重和压缩,磁盘空间的使用就会变得非常复杂。
甚至还有关于释放空间(freeing space)的问题。
在许多ZFS部署中,删除文件实际上不会释放空间。在大多数情况下,由于快照和元数据,删除实际上会略微增加磁盘空间使用量。这些文件使用的空间将分配给最新的快照。要成功管理ZFS,您必须了解底层功能的工作方式,以及删除数据时ZFS的操作。
在使用快照和克隆的文件系统上,新释放的空间不会立即出现。许多ZFS操作异步(asynchronously)释放空间,因为ZFS更新引用该空间的所有块。池的 freeing 属性显示ZFS仍然需要从池中回收多少空间。如果一次释放一大堆空间,则可以观察 freeing 特性的减少和可用空间的增加。ZFS回收空间的速度取决于硬件、负载量、池设计、碎片级别以及空间的使用方式。
异步释放空间很容易理解:您可以查看 freeing 属性并查看其下降的速度。但对于外行来说,ZFS的磁盘使用似乎更奇怪。假设您有一组数据集快照,并且它们的父数据集已满。(我们在第7章中介绍了快照,但现在请容忍我们。)您从数据集中删除了几个大型ISO。删除这些文件不会释放任何空间。为什么不呢?
这些ISO文件仍然存在于较旧的快照中。ZFS知道文件在当前数据集中不存在,但如果您查看快照目录,就会看到这些文件。ZFS必须为较旧的快照保留这些已删除文件的副本,只要快照引用该数据。快照内容是只读的,因此删除这些大文件的唯一方法是删除快照。如果有多个快照,则磁盘使用会变得更复杂。克隆(第7章)构建在快照上,其行为方式相同。
要准确地理解特定数据集如何使用磁盘空间,需要花一些时间了解其属性。
要查看磁盘空间的确切位置,使用 zfs list -o space :
xxxxxxxxxx# zfs list -o spaceNAME AVAIL USED USEDSNAP USEDDS USEDREFRESERV USEDCHILDzroot 874G 17.5G 0 144K 0 17.5Gzroot/ROOT 874G 1.35G 0 144K 0 1.35Gzroot/ROOT/default 874G 1.35G 0 1.35G 0 0zroot/usr 874G 12.5G 0 454M 0 12.0G...AVAIL 列显示了池上每个数据集的可用空间量。ZFS在池中的所有数据集之间共享可用空间。
此值来自ZFS的 available 属性。
USED 列显示了此数据集占用的空间量以及由此产生的所有内容。快照、ZVOL、克隆、常规文件和其他任何使用空间的内容都计入此量。
当ZFS写入新文件、创建快照和子数据集或进行其他更改时,此值可能会滞后几秒钟。
此值来自数据集的 used 属性。
USEDBYSNAP 列显示快照专用的空间量。当第一次创建快照时,快照几乎不占任何空间。因为它与原始数据集几乎完全相同。然而随着数据集的变化,快照也会增长。
由于同一数据集的多个快照可能引用相同的数据,因此很难说删除单个快照是否会释放此空间的任何部分。然而,完全删除此数据集的所有快照肯定会释放出这么多空间。
此值来自数据集的 usedbysnapshots 属性。
USEDDS 列显示了此数据集上文件使用的空间量。它不包括快照、保留、子数据集或其他特殊的ZFS功能。
此值来自数据集的 usedbydataset 属性。
USEDBYREFRESERV 列显示数据集的重新保留使用的空间,不包括其子数据集。
此值来自数据集的 usedbyfreserv 属性。
USEDCHILD 列显示此数据集的子数据集使用了多少空间。
此值来自数据集的 usedbychildren 属性。
将上一节中 zfs list 中的 zroot/usr 条目与详细的空间描述进行比较。 zfs list 结果表示数据集使用12.5 GB,引用454 MB。通过将特定于空间的列表划分为不同的类别,很明显,该数据集使用454MB,而子数据集占用12GB。
每当您调查磁盘使用情况时,请使用 zfs list -o space 。
实例:
xxxxxxxxxx# zfs list -r -o space zdata/filmzfs list 的 -o 选项后面可以跟若干属性名称,各属性之间用逗号隔开。
zfsprops 中的原生属性之一。name 显示数据集的名字。space 显示文件系统和卷的空间使用属性,与以下写法效果相同:
-o name,avail,usedsnap,usedds,usedreserv,usedchild -t filesystem,volum 。例如:
xxxxxxxxxx# zfs list -o name,creation,available -r zdata/filmNAME CREATION AVAILzdata/film Tue Jun 4 14:23 2024 3.97Tzdata/film/4k Tue Jun 4 14:23 2024 3.97Tzdata/film/documentary Wed Jun 5 7:56 2024 3.97Tzdata/film/movies Wed Jun 5 10:38 2024 3.97Tzdata/film/mp3 Thu Jun 6 8:09 2024 3.97Tzdata/film/mv Thu Jun 6 9:55 2024 3.97T有时,您并不关心单个数据集的空间使用情况。只有池可用的空间作为一个整体很重要。如果查看池的属性,您将看到与已使用和可用空间量非常相似的属性。它们是,但池的空间属性包括奇偶校验信息所需的空间。它们不能反映池中可以容纳的数据量。
如果您有一个镜像或条带化池,则池空间信息相当接近于现实。如果使用RAID-Z1,则会丢失池中每个虚拟设备的奇偶校验空间提供程序。RAID-Z2的成本是每个VDEV两个磁盘,RAID-Z3的成本是每VDEV三个磁盘。理论上,虽然您可以使用这些属性、池的当前使用情况和一些数学知识来猜测您正在使用多少空间,但有一种更简单的方法:询问 zfs(8) 关于池的根数据集。
xxxxxxxxxx# zfs list zrootNAME USED AVAIL REFER MOUNTPOINTzroot 37.7G 854G 144K none此池使用了37.7GB,剩余854GB空间。
因此,ZFS具有各种奇特的功能,可以对其磁盘使用情况的显示进行切片和切分。在使用 df(1) 查看磁盘使用情况几十年后,我们中的许多人都不愿意改变。然而,当您使用ZFS时,久负盛名的 df(1) 和许多其他工具不仅不太理想,它们实际上是不正确的,并且为ZFS给出了错误或令人困惑的答案。我们将使用 df(1) 作为示例,但许多其他工具也有类似的问题。
传统的文件系统由单个分区组成。该分区的大小取决于在底层磁盘上分配的块数。df(1) 工具在每个已安装的文件系统上迭代,并显示分区的大小、当前使用了多少空间以及剩余的可用空间。
遍历(walking through)文件系统对于ZFS不起作用,因为数据集不是文件系统。ZFS将每个数据集公开给操作系统,就像它是一个单独的文件系统一样。数据集没有最大大小(除非它有配额)。虽然可以设置数据集大小的上限和下限,但所有ZFS数据集都可以访问池中的所有可用可用空间。
为了提供与传统 df(1) 工具的某种兼容性,ZFS撒了一个小谎。由于ZFS数据集在传统的文件系统意义上没有“大小”,因此它将使用的空间和整个池的可用的自由空间相加,并将该值表示为数据集的“大小”。
请看上一节中的示例池。 zroot/ROOT/default 数据集使用1.35 GB的空间,并且有874 GB的可用空间。总大小为875.35 GB。然后查看 zroot/usr 数据集。它使用了12.5 GB,并且有874 GB的空闲空间,总共886.5 GB。
现在检查这些数据集的一些实际 df(1) 输出。
xxxxxxxxxx# df -hFilesystem Size Used Avail Capacity Mounted onzroot/ROOT/default 875G 1.4G 874G 0% /zroot/usr 874G 454M 874G 0% /usr...根文件系统为875 GB,/usr 为874 GB,这两个分区的总容量为1749 GB,可用容量为1748 GB。对于1 TB的磁盘来说,这相当令人印象深刻,不是吗? Capacity 列显示了文件系统的使用百分比,这类似于伪造的。
随着数据集的增长,可用空间量也在减少。根据 df(1) ,文件系统随着空间的使用而收缩,随着空间的释放而增长。
像 df(1) 这样的工具以及用于传统文件系统的大多数其他监视工具给出了错误的答案。当心他们!虽然它们看起来可以快速检查,但继续使用这些工具会进一步养成坏习惯。不良的系统管理习惯会导致疼痛和中断。监视数据集的可用空间时,请确保测量的是实际的可用空间量,而不是使用的百分比。如果显示“使用百分比(percent used)”的传统工具给出了有意义的结果,那只是偶然的。您的监控系统需要ZFS特定的工具。
当使用用于传统文件系统的其他工具查看时,此行为具有有趣的副作用。通过Samba在Windows机器上装载的ZFS数据集将仅显示已使用的极小空间量,池中的剩余空间量作为可用空间。当池中充满数据时,Windows会看到驱动器收缩(shrink)。
使用ZFS时,养成用准确工具管理的习惯。
ZFS的灵活性意味着用户和应用程序可以使用可用的磁盘空间。这是非常有价值的,特别是在长寿命的系统上,但有时这正是您不想要的行为。您不希望 /var/log 扩展之类的数据集填满磁盘,相反,您希望确保数据库之类的关键数据集获得所需的空间。如果主数据库空间不足,因为Jude暂时将他收集的非法盆栽蕨类植物照片藏在他的主目录中,那么您将有一次不愉快和不必要的会议。这就是配额和预留的来源。
配额(quota)指示数据集及其所有后代可以使用的最大空间量。如果在挂载为 /home 的数据集上设置100 GB的配额,/home 及其下的所有数据集和快照使用的空间总量不能超过100 GB。
预留(reservation)指定为数据集预留的空间量。为了确保数据库始终有写入其文件的空间,请使用保留来为该数据集留出一定量的磁盘空间。
我们将首先讨论预留,然后讨论配额。
预留为数据集及其子级预留了一大块磁盘空间。系统将不允许其他数据集使用该空间。如果池耗尽空间,则保留的空间仍可用于写入该数据集。
假设我们将1 TB池中的100 GB预留给 /var/db ,我们的数据库在其中填充其数据文件。该数据集中有大约50GB的数据。日志文件疯狂运行,并填充池的其余部分。我们将从系统上的其他程序收到错误消息,说磁盘已满,但数据库程序在 /var/db 中仍然有可用空间。它可能会抱怨不能将程序日志写入 /var/log/db ,但这是一个单独的问题。
ZFS使用两个ZFS属性管理预订:refreservation 和 reservation 。
refreservation 影响数据集的引用(referenced )数据,即它排除快照、克隆和其他子体。reservation 包括子数据集、快照等。例如,请查看 zfs list 中的此片段。
xxxxxxxxxx# zfs listNAME USED AVAIL REFER MOUNTPOINTzroot/usr 12.5G 874G 454M /usrzroot/usr/local 1.84G 874G 1.84G /usr/localzroot/usr/obj 6.89G 874G 6.89G /usr/objzroot/usr/ports 1.97G 874G 816M /usr/ports…zroot/usr 数据集被挂载为 /usr 。它“使用”12.5 GB,包括 /usr/local、/usr/obj 等子数据集。它仅指454 MB,这意味着主 zroot/usr 数据集上的数据量不足半GB。
如果我们在 zroot/usr 上设置1GB的预留,那基本上是没有意义的。子数据集中的现有文件远远超过了这一点,并且一些非灾难性的东西将这些子数据缩减到小于1GB的可能性可以忽略不计。
然而,如果在 zroot/usr 上设置1GB的 refreservation ,则它仅影响 zroot/usr 上的文件。子数据集被排除在外。数据集当前已半满,因此它将有空间写入更多文件。
这是一个极端的例子,但有点人为。假设您希望确保所有用户都获得至少1 GB的磁盘空间。为每个用户的主目录创建单独的数据集,并为每个用户分配一个预留。
您还可以嵌套预留。假设您有两个数据集,zroot/var/log 和 zroot/var/log/db ,后者专门用于您的数据库服务器。您希望数据库服务器日志始终至少有10GB,因此将保留分配给 zroot/var/log/db 。然后您需要20 GB用于通用服务器日志。如果20 GB应包括数据库日志,请使用预留。如果它不应包括数据库日志,请使用 refreservation 。
数据集可以同时具有保留和引用保留。您可能会说,数据集 zroot/var/log/db 对当前日志文件具有10GB的 refreservation ,但设置了一个更大的保留,以便可以拍摄数据集的快照,并单独计算它们的使用情况。
试图违反预留会产生“空间不足”错误。当该错误出现时,即使您知道您仍然有可用的磁盘空间,请检查您的预留。预留的数据集将显示可用空间,但所有其他数据集都将满。
您可以分别查看预订和预订,但我们更喜欢一次获得所有预订信息。您可以通过运行 zfs get -o reservation,refreservate,usedbyrefreservalation 来查看特定的属性列表:
xxxxxxxxxx# zfs get reservation,refreservation,usedbyrefreservation zroot/var/logNAME PROPERTY VALUE SOURCEzroot/var/log reservation none defaultzroot/var/log refreservation none defaultzroot/var/log usedbyrefreservation 0B -但Lucas太懒了,无法键入所有这些内容,他是主要作者,因此本例使用 grep(1) 。
xxxxxxxxxx# zfs get all zroot/var/log/db | grep reservzroot/var/log/db reservation none defaultzroot/var/log/db refreservation none defaultzroot/var/log/db usedbyrefreservation 0 -也可以使用 zfs list -o name,reservation,refreservation,usedbyrefreservation 查看对应的信息:
xxxxxxxxxx# zfs list -o name,reservation,refreservation,usedbyrefreservation zroot/var/logNAME RESERV REFRESERV USEDREFRESERVzroot/var/log none none 0B此数据集没有保留或引用保留集。让我们设置一些。
usedbyrefreservation 属性显示如果删除 refresernation ,该数据集上将释放多少空间。
像设置任何其他ZFS属性一样设置预订。这里,我们在 /var/log/db 上设置了 refreservation ,在 /var/log 上设置了预留。
xxxxxxxxxx# zfs set refreservation=10G zroot/var/log/db# zfs set reservation=20G zroot/var/log无论如何,该主机现在将为数据库日志保留10 GB,为日志文件保留20 GB,包括数据库目录。我们对数据库日志使用了 refreservation ,因为我们不希望根据该保留计算快照。
要删除保留,请将其设置为 none 。
xxxxxxxxxx# zfs set reservation=none zroot/var/log其他数据集现在可以使用该空间。
quota 是数据集、用户或用户组可以使用的最大空间量。所有这些配额都是基于每个数据集设置的。我们将从数据集配额开始,然后研究用户和组配额。
如果要设置数据集可以占用的最大空间量,请使用配额。例如,您可以决定 /tmp 最多只能使用10 GB,或者 /home 最多只能使用200 GB,或者任何其他对您有意义的限制。
与预留一样,ZFS为配额使用两个属性:quota 和 refquota 。
quota 属性设置数据集及其所有子级可以使用的最大空间量。refquota 属性建立数据集可以使用的最大空间量,不包括其子级。如果需要排除快照和子数据集的配额,请使用 refquota 属性。
为什么要使用 refquota 而不是 quota ?假设每个用户的主目录是其自己的数据集,并且用户无法创建快照。大多数人不能,大多数人不知道怎么做。如果您自动创建快照,就像我们在第7章中所演示的那样,那么快照使用的空间将从用户的帐户中扣除。磁盘空间不足的用户可能会删除一些文件,但发现它们尚未释放任何空间。向用户收取他们无法控制的磁盘空间费用可能是不公平的。
要在数据集上配置配额,请分配配额和/或 refquota 属性。
在Reservations部分中,我们为 zroot/var/log 数据集中的系统日志预留了20 GB,确保日志始终具有至少20 GB的空间。一个更常见的问题是日志疯狂运行并吸收所有可用磁盘空间,导致系统崩溃。您的监控系统应该会捕获此错误,但在日志数据集上建立配额也是有意义的,以便有人在 /etc/syslog.conf 中取消注释 /var/log/all.log ,不会在一天后使该框崩溃。
这里,我们在 zroot/var/log 上设置配额。
xxxxxxxxxx# zfs set quota=100G zroot/var/log日志文件最多可以使用100 GB,包括快照、子数据集和其他所有内容。
可以使用 refquota 单独限制引用数据的数量。这不包括子数据集和快照。限制整个数据集的大小和数据集的引用数据可以帮助您控制快照的大小。例如,将 refquota 设置为10 GB和 quota 设置为100 GB将告诉您,即使数据完全更改,也始终可以有10个快照。类似地,如果要排除子数据集,请使用 refquota 。
xxxxxxxxxx# zfs set refquota=50G zroot/var/log# zfs set refquota=50G zroot/var/log/db# zfs set quota=500G zroot/var/log这里,我们有两个日志数据集的单独引用配额,以及两个数据集的配额。如果每个数据集可以单独引用高达50 GB的数据,则500 GB配额意味着无论数据如何更改,每个数据集至少可以有四个快照。
使用以下命令可以查看数据集的配额和引用配额:
xxxxxxxxxx# zfs get all zroot/home | grep quotazroot/home quota none defaultzroot/home refquota none default/home 目录没有配额。用户可以将硬盘驱动器填满到其限制。
配额更改数据集的最大大小和数据集中的可用空间。该池有数百GB的空闲空间,但该数据集上的 zfs list 另有说明。
xxxxxxxxxx# zfs list zroot/var/logNAME USED AVAIL REFER MOUNTPOINTzroot/var/log 25.0G 75.0G 5.01G /var/logzroot/var/log 数据集上有25 GB,75 GB可用。ZFS知道数据集上有100GB的配额,并且它适当地显示了利用率。您只是通过设置配额来模拟传统分区,但不要运行 df(1) !首先,查看 zroot/var/log 的子数据集。
xxxxxxxxxx# zfs list zroot/var/log/dbNAME USED AVAIL REFER MOUNTPOINTzroot/var/log/db 20.0G 85.0G 10.0G /var/log/dbZFS知道父数据集的配额为100 GB,因此还设置了子数据集的最大大小。如果 /var/log 有75 GB的空闲空间,而 /var/log/db 有85 GB的空闲,这是否意味着这两个分区有(75+85=)160 GB的可用空间?不,因为就像池中的可用空间一样,这两个条目都引用相同的可用空间。数据集 zroot/var/log/db 条目似乎有更多的可用空间,因为其父数据集中的数据不会反映在子数据集的使用中。
如果用户或进程试图写入会使数据集超过其配额的内容,它将得到配额错误。
xxxxxxxxxx# cp script.sh testscript.shcp: testscript.sh: Disc quota exceeded您需要释放一些空间,但请记住,快照可能会使其复杂化,如本章前面的【释放空间】中所述。如果您同时设置了 quota 和 refquota ,则用户可能能够删除文件并释放空间,即使这会增加文件系统快照的大小。
用户和组配额控制用户或组可以写入数据集的数据量。与数据集配额一样,用户和组配额也基于每个数据集进行控制。
用户和组配额不适用于子文件系统、快照和克隆。必须将配额应用于希望它们影响的每个数据集。
zfs userspace 命令允许您查看数据集中每个用户使用了多少空间。在这里,我们在测试系统上检查 zroot/home 数据集。具有复杂数据集的系统可能需要几分钟来运行 du(1) ,但 zfs userspace 几乎在瞬间找到每个用户拥有的所有文件。
xxxxxxxxxx# zfs userspace zroot/homeTYPE NAME USED QUOTAPOSIX User 179 7.29M nonePOSIX User mwlucas 1.16G nonePOSIX User root 298M none用户 mwlucas 有1.16 GB的文件,这并不令人惊讶。root用户在 /home 中有298MB的文件,这有点令人惊讶,但并不令人震惊。然而,用户 179 在该数据集中有7.29MB的文件。该系统没有用户 179 ,这就是为什么用户以UID而不是用户名显示的原因。一些挖掘表明,Lucas曾经在提取源代码tarball时使用 tar 的 -p 参数,从而保留了原始文件所有权。
这些用户都没有配额。
zfs groupspace 命令显示每个组所拥有的文件使用的空间量。更有趣的是,我正在检查 zroot/usr/local 数据集上的组所有权。
xxxxxxxxxx# zfs groupspace zroot/usr/localTYPE NAME USED QUOTAPOSIX Group _tss 25.5K nonePOSIX Group bin 93.5K nonePOSIX Group kmem 128K nonePOSIX Group messagebus 392K nonePOSIX Group polkit 115K nonePOSIX Group wheel 1.85G none如果服务器支持多个组,例如开发团队、研究组或不同BSD变体的爱好者,则可以为每个组或用户分配配额,以限制其磁盘使用。
使用 userquota 和 groupquota 属性来分配用户和组配额。要指定配额所属的用户或组,请提供属性名称、@符号以及用户或组名称。为用户 mwlucas 提供配额,例如,使用userquota@mwlucas.
xxxxxxxxxx# zfs set userquota@mwlucas=1G zroot/home上一节显示了 mwlucas 帐户中有超过1GB的数据。 mwlucas 帐户超过了配额,并且该用户每次尝试创建文件时都会收到错误。
xxxxxxxxxx$ touch testtouch: test: Disc quota exceeded类似地,使用 groupquota 属性、@符号和组名分配组配额。
xxxxxxxxxx# zfs set groupquota@staff=10G zroot/home如果用户反复滥用 /tmp 等共享目录,请为它们分配限制配额。
x# zfs set userquota@mwlucas=10m zroot/tmp该用户可以使用SSH代理转发等功能,但他不能提取巨大的tarball并独占共享的临时空间。
要删除配额,请将配额设置为 none 。
使用以下命令查看用户或组的配额:
xxxxxxxxxx# zfs get userquota@mwlucas zroot/tmpNAME PROPERTY VALUE SOURCEzroot/tmp userquota@mwlucas 10M local现在,您可以让您的团队就其磁盘空间使用情况彼此争吵,而不会占用您宝贵的时间。恭喜你!
不能增加现有磁盘的大小,但可以更改数据使用该磁盘的方式。几十年来,系统管理员一直在压缩文件,以减少它们占用的空间。我们编写了各种shell脚本,在我们知道可以安全压缩的文件上运行我们首选的压缩算法,并且我们总是在寻找可以压缩以节省空间的其他文件。我们都知道以前未知的日志文件,它会扩展到填充分区并触发警报。
ZFS通过在文件系统级别实时压缩文件来解决这个问题。守护程序写入的日志文件?ZFS可以在编写时对它们进行压缩,从而使所有这些脚本变得不相关。这也摊销了压缩成本,因为系统在持续的基础上压缩所有内容,而不是在凌晨3点疯狂的磁盘颠簸中。
然而,压缩带来了成本。压缩和解压缩需要CPU时间,因此在任何地方盲目地启用最严格的gzip压缩都会增加磁盘性能的另一个限制。然而,任何性能损失通常都不是由磁盘活动的减少所弥补的。ZFS包括专门为文件系统使用而设计的压缩算法。
ZFS压缩基于每个数据集工作。您可以为某些数据集启用压缩,但不能为其他数据集启用。
使用 compression 属性启用和禁用压缩。这里我们检查压缩设置。
xxxxxxxxxx# zfs get compress zroot/usrNAME PROPERTY VALUE SOURCEzroot/usr compression off default通过设置 compression 属性来启用压缩。默认的压缩算法 LZJB 不是ZFS提供的最有效的算法。几乎在所有情况下都应该使用 LZ4 压缩。这里,我们在 zroot 池上的所有数据集上启用LZ4压缩,但在 zroot/var/cdr 数据集上指定 gzip-9 。
xxxxxxxxxx# zfs set compress=lz4 zroot# zfs set compress=gzip-9 zroot/var/cdrZFS在将文件写入磁盘时压缩文件。如果您有一个充满文本文件的数据集,则添加压缩不会使它们收缩。要减少文件使用的磁盘空间,必须在启用压缩后重写所有文件。
ZFS支持几种压缩算法。
默认的 LZJB 是专门为文件系统使用而设计的。它可以以适当的压缩比快速压缩和解压缩块。然而,它不是日常使用的最佳压缩算法。
LZ4 算法是一种更新、更快的特定于文件系统的压缩算法。它在所有方面都优于 LZJB 。并非所有的数据都是可压缩的,但 LZ4 可以快速检测不可压缩的文件,并且不会尝试压缩它们。为数据集启用压缩时,请使用 LZ4 ,除非您有 gzip 压缩的特定用例。
ZLE 算法压缩文件中的零字符串。它是一个最小的压缩系统,对于大多数文件不是特别有用。LZ4 比 ZLE 有效得多,即使在有很多零的文件上也是如此。
对于特殊情况,ZFS支持 gzip 压缩。gzip 比 LZ4 使用更多的CPU时间,但对于某些数据集可能更有效。gzip 所需的额外CPU时间使文件系统变慢,但对于不经常访问的数据,节省磁盘空间可能是值得的。
gzip 有九个压缩级别,从1(最快但最不有效)到9(最慢但最具攻击性)。使用破折号和级别指定gzip压缩级别。
xxxxxxxxxx# zfs set compress=gzip-1 zroot/var/log指定 gzip 但没有指定级别的话,ZFS默认使用级别 6 。
有几个属性可以深入了解ZFS压缩数据的效果。
compressratio 属性显示压缩如何影响数据集及其所有子集;refcompressratio 属性允许查看压缩如何影响该数据集的引用数据;logicalreferenced 和 logicalused 属性仅适用于压缩场景。数据集的引用空间包括压缩的影响,但 logicalreferenced 属性不包括压缩。used 属性显示数据集及其所有子集上实际消耗的空间量,而 logicalused 显示数据集中未压缩的数据量。当您一起研究所有这些时,您可以很好地了解压缩对数据的影响。
您如何判断数据是否可以从压缩中受益,或者不同的算法如何影响文件大小?获取一些典型的数据文件并测试它们。使用 du(1) 或 ls –ls 查看文件在磁盘上的实际大小。在测试自己的数据时,您需要使用实际数据的一大堆不同的文件。在这个例子中,Lucas使用了从古腾堡项目下载的人类基因组项目。
xxxxxxxxxx# du hgp.txt280721 hgp.txt未压缩的情况下,这个文件占用280,721个块,或者大约274MB。
我们的测试数据集称为 db 。该数据集上没有其他数据,因此我们可以准确地评估压缩对该特定文件的影响。既然我们知道了测试文件的未压缩大小,那么就启用压缩并看看会发生什么。
xxxxxxxxxx# zfs set compression=on db再查看文件大小:
xxxxxxxxxx# du hgp.txt280721 hgp.txt文件大小没有改变,但我们启用了压缩。发生了什么事?请记住,压缩、重复数据消除和类似功能仅适用于启用该功能后写入的文件。我们必须删除文件并将其放回。
xxxxxxxxxx# rm /db/*# cp /home/mwl/hgp.txt /db等几秒钟让ZFS完成写入动作,再次查看:
xxxxxxxxxx# du /db/hgp.txt139577 /db/hgp.txt文件仅使用了139577个块,大约136MB。大约缩小了一半,像数据集属性显示的那样:
xxxxxxxxxx# zfs get compressratio,refcompressratio dbNAME PROPERTY VALUE SOURCEdb compressratio 2.01x -db refcompressratio 2.01x -refcompressratio 等于 compressratio ,因为我们在此数据集上只有一个数据块,而此池上仅有一个数据集。在更复杂的池上,值可能会有所不同。
因此,默认算法将大小减少了一半。让我们试试更有效的 lz4 。
xxxxxxxxxx# zfs set compression=lz4 db重新复制该文件以触发LZ4压缩,等待几秒钟,让ZFS进行记帐,然后查看发生了什么。
xxxxxxxxxx# du /db/hgp.txt146076 /db/hgp.txtLZ4 将该数据压缩到142 MB。LZ4 在该特定文件上不如 LZJB 有效。这并不可怕,不同的算法在不同的数据上工作不同。
gzip 会进一步改进吗?
xxxxxxxxxx# zfs set compress=gzip-1 db/text重新复制文件,再次查看:
xxxxxxxxxx# du /db/hgp.txt74104 /db/hgp.txt该数据现在使用约72 MB,数据集现在的压缩比为3.78。gzip 显然更适合这种特定的数据。压缩几乎使我们的有效磁盘空间增加了四倍。虽然这相当令人印象深刻,但让我们调大音量。
xxxxxxxxxx# zfs set compress=gzip-9 db/text# cp /home/mwl/hgp.txt /db/# du /db/hgp.txt63614 /db/hgp.txt将压缩提高到 gzip-9 将这个274 MB的文件减少到62 MB,compressratio (压缩比)为4.41。gzip-9 将我们可以存储的数据量增加了四倍多。
然而,这个例子是作弊的。真的,真的作弊。正如在物理考试之前,“在手掌上写公式”作弊。
除了古腾堡计划增加的样板外,人类基因组计划完全由四个字母组成。它可能是存在的最冗余、最可压缩的真实世界数据。您不能期望从大多数真实世界的数据中得到这一点。
通常,我们建议仅在迫切需要时才从LZ4更改压缩算法,并且额外的CPU开销和较慢的磁盘访问不会影响实际工作。
不久前,Lucas在一家电话公司工作。该公司为通过其设备进行的每个电话保留了十多年的纯文本呼叫详细记录(call detail records,CDRs)。这些记录通常在午夜运行报告。有时,欺诈调查人员需要使用 grep(1) 和 awk(1) 等工具访问这些报告。对于这个用例,启用 gzip-9 压缩非常有意义。用 du(1) 测量,ZFS以大约8:1的速度压缩文件。然而,如果我们需要定期与这些文件交互,LZ4和额外的几百美元硬盘驱动器将更有意义。
先看一下示例中的这些属性:
xxxxxxxxxx# zfs get all db | grep referencedb/text referenced 48.7M -db/text logicalreferenced 220M -此数据集使用48.7 MB的磁盘空间。忽略压缩时,数据集具有220MB的数据。压缩数据集可以存储比其大小更多的“逻辑数据(logical data)”。
这就是压缩的有效性(effectiveness)真正发挥作用的地方。读取和写入数据最慢的部分是将其放在存储介质上。物理介质是磁盘事务中最慢的部分。将48.7 MB写入磁盘所需的时间约为将220 MB写入磁盘的22%。通过启用压缩,您可以将存储时间减少78%,但代价是占用少量CPU时间。如果磁盘可以写入100 MB/s,则写入48.7 MB的压缩数据大约需要半秒钟。如果从写入数据的应用程序的角度来看,您实际上在半秒钟内写入了220 MB,实际上是440 MB/s。我们敢打赌,您认为您的笔记本电脑磁盘无法管理它!
如果要存储许多小文件,则压缩的效率较低。小于扇区大小的文件将获得分配给它们的整个块。如果您想要真正有效的压缩,请使用具有实际512字节物理扇区的磁盘,并告诉ZFS使用该扇区大小。
压缩不是完美的。顺序访问和随机访问可以改变压缩的性能。始终在您的环境中使用自己的数据进行测试。压缩工作得足够好,以至于FreeBSD在其默认安装中启用 lz4 压缩。
大多数CPU大多空闲。让懒惰的生物处理一些数据!
要停用(deactivate)压缩,应将数据集的 compression 属性设置为 off 。
就像激活压缩只会影响新写入的文件一样,停用压缩只影响新数据。压缩文件在重写之前保持压缩状态。ZFS足够聪明,可以知道文件是压缩的,并在访问时自动解压缩,但它仍然有开销。
除非重写所有文件,否则无法清除数据集中的所有压缩痕迹。最好的方法是重新创建数据集。
文件反复重复相同的数据,排列略有不同。多个文件包含更多的重复。系统上一半以上的数据可能与在其他位置找到的数据重复。ZFS可以识别文件中的重复数据,提取并记录它,因此每个数据只存储一次。它非常类似于压缩。在某些情况下,重复数据消除(deduplication )可以减少磁盘使用。
存在许多重复数据消除系统。在一个极端情况下,您可以在逐字节级别重复数据消除所有数据。您可以通过识别和记录每个字母和标点符号的位置来消除本书的重复数据,但记录将比实际的书大。在另一个极端,您可以通过只记录一次来消除整个文件的多个副本。
ZFS快照可以说是对文件系统数据进行重复数据消除。对于重复数据消除文件,ZFS在文件系统块级别进行重复数据消除(由 recordsize 属性显示)。这使得ZFS能够很好地删除相同文件的重复项,但它意识到,只有当文件系统块完全对齐时,文件才是重复的。使用较小的块可以提高重复数据消除的工作效率,但会增加内存需求。ZFS仅存储一次相同的块,并将重复数据消除表存储在内存中。
在逐个数据集的基础上启用重复数据消除。每次通过读取或写入来访问重复数据集上的任何文件时,系统都必须参考重复数据消除表。为了有效地进行重复数据消除,系统必须具有足够的内存来容纳整个重复数据消除表。ZFS将重复数据消除表存储在磁盘上,但如果主机每次需要访问文件时都必须参考磁盘上的副本,则性能将下降到一定程度。(主机必须在启动时从磁盘读取重复数据消除表,因此每次重新启动时都会出现磁盘抖动。)
虽然重复数据消除听起来非常酷,但在考虑启用重复数据消除之前,您必须知道数据的重复数据消除能力和所需的内存量。
对于粗略的近似,您可以假设1 TB的重复数据消除数据使用约5 GB的RAM。通过查看数据池并进行一些计算,您可以更接近地估计特定数据的内存需求。我们建议始终进行数学计算并计算数据需要多少RAM,然后使用最悲观的结果。如果数学给出的数字大于5GB,请使用您的数学。如果不是,则假设每TB 5 GB。
如果您在RAM上缩短系统,性能将像Wile E.Coyote一样直线下降。不要对自己这样做。
重复数据消除数据集上的每个文件系统块使用约320字节的RAM。ZFS的 zdb(8) 工具可以分析池,以查看将使用多少个块。使用 -b 标志和要分析的池的名称。
xxxxxxxxxx# zdb -b dataTraversing 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: 139025ganged count: 0bp logical:18083569152 avg: 130074bp physical: 18070658560 avg: 129981 compression: 1.00bp allocated: 18076997120 avg: 130026 compression: 1.00bp deduped: 0 ref>1: 0 deduplication: 1.00SPA allocated: 18076997120 used: 1.81%additional, non-pointer bps of type 0: 21Dittoed blocks on same vdev: 1183注:10T左右的池,以上操作可能需要1小时左右。
time remaining 计数器实际上并不完全糟糕,这是好事,因为该进程可以运行很长时间,这取决于磁盘速度和利用率。一旦用完,您将得到池的统计分析。
bp count 显示了存储在池中的ZFS块大小的总数。这个池使用了139025个块。ZFS默认使用最大块大小128 KB,而小文件使用较小的块。如果池中有许多小文件,则需要更多的内存。
在底部的第三行中,used 条目显示该池已使用1.81%(或0.0181)。假设该池中的数据在增长时将保持相当一致。将已使用的块数四舍五入为140000。将使用的块除以块的满程度,我们可以看到完整的池将有大约(140000/0.0181=)7734806个块。在每个块320字节的情况下,该数据使用2475138121字节的RAM,或大约2.3 GB。
这还不到经验法则的一半。假设此池上的ZFS重复数据消除表每TB存储需要5 GB RAM。
ZFS允许重复数据消除表等元数据仅占用系统内存的25%。(实际上,它是自适应替换缓存(ARC)的25%,但我们将在 《FreeBSD Mastery:Advanced ZFS》中详细介绍这一点。)每TB的重复数据消除池意味着系统需要至少20 GB的RAM。即使您根据块使用情况得出了更具希望的数学公式,其中每TB的磁盘需要2.3 GB的RAM,25%的限制意味着每TB的删除重复的池需要大约10 GB的内存。(在 《FreeBSD Mastery:Advanced ZFS》中,我们讨论调整此限制,以便希望脚踏实地拍摄自己的人可以很好地完成这一任务。)
ZFS可以模拟去重,并很好地估计数据的去重效果。在池上运行 zdb -S ,会得到一个很好的利用率和常见元素的直方图。最后一行的结果可用来参考:
xxxxxxxxxx# zdb -S dataSimulated DDT histogram:...dedup = 3.68, compress = 1.00, copies = 1.00, dedup * compress / copies = 3.68我们的池数据可以重复3.68次。如果此池中的所有数据都是这种可重复数据消除的,则每TB存储中可以容纳3.68 TB的数据。然而,该数据异常冗余。相比之下,在Lucas的桌面上,包含FreeBSD操作系统、用户程序和主目录的 zroot 池大约为1.06个可重复数据消除池。
这还不错。请注意,我们仍然需要每TB重复数据消除池具有20 GB RAM的机器,但我们现在可以根据当前的硬件需求进行成本/效益(cost/benefit)计算。您还可以将测试数据的重复数据消除能力与其可压缩性进行比较。
内存开销值得吗?这取决于内存成本与存储成本。
每次我们评估数据的重复数据消除能力和可压缩性,然后针对每种情况定价硬件时,我们都会发现,使用更快的磁盘和更多的CPU来增强压缩比加载用于重复数据消除的内存更具成本效益。重复数据消除不会提高磁盘读取速度,尽管它可以提高缓存命中率。它仅在发现重复块时提高写入速度。重复数据消除还显著增加了释放数据块所需的时间,因此销毁数据集和快照的速度可能会变得非常慢。压缩也会影响这些性能,但不会施加这些惩罚。
重复数据消除可能只有在磁盘空间有限、成本高昂且性能非常高的情况下才有意义。如果您需要将大量重复数据塞入SSD池中,重复数据消除可能适合您。
然而,每个人的数据都是不同的,因此在做出决定之前请检查您的数据。
ZFS的 dedup 属性值(on 或 off)控制去重:
xxxxxxxxxx# zfs set dedup=on data/data1重复数据消除现在在此数据集上处于活动状态。
与压缩一样,重复数据消除仅影响新写入的数据。激活重复数据消除不会神奇地消除池中已存在的重复数据。为了获得最佳结果,请在首次创建数据集时,在向其写入任何数据之前,激活重复数据消除。
要关闭重复数据消除,请将数据集的重复数据消除属性设置为关闭。
xxxxxxxxxx# zfs set dedup=off data/data1与压缩一样,禁用重复数据消除不会神奇地重复所有文件。重复数据消除的文件保持重复数据消除状态。如果关闭 dedup 是因为它使系统性能糟糕,则关闭它不会提高性能。只有删除重复数据消除的文件才能提高性能。不能从数据集中清除 dedup 的所有跟踪。最好使用 zfs send 和 zfs receive 将数据发送到不使用重复数据消除的新数据集。
您的最佳选择可能是不使用重复数据消除。重复数据消除是一项伟大的技术,需要它的人确实需要它。然而,我们大多数人都没有可重复数据。不要仅仅因为功能很酷就启用它们。
在开始时正确选择磁盘空间管理策略将为您节省许多未来的痛苦。
最好的选择可能是不使用去重。