传统文件系统在创建分区的时候会限制分区的大小,随着数据量增加,可能会没有足够的空间来容纳所有数据。
ZFS通过池化可用空间来解决这个问题,每个数据集都可以访问池中所有可用空间。
也可以使用配额(quota)限制数据集的大小,或通过保留(reservation)来保证数据集最小空间量。
传统文件系统的核心问题归结为缺乏灵活性。
数据集是一个命名的数据块。这些数据可能是:
类似于传统的文件系统; 一个原始的块设备; 其他数据的副本; 任何可以塞进磁盘的东西。
数据集具有层次关系。单个存储池是每个顶级数据集的父级。
每个数据集都可以有子数据集。
数据集继承了其父级的许多特性。
zfs命令有一系列子命令。
ZFS目前包括物种类型的数据集:
每个ZFS数据集都有一系列控制器操作的属性,允许管理员控制数据集的执行方式以及保护数据的谨慎程度。可以精确地调整每个数据集。
系统管理员可以将单个数据集地控制权委托给另一个用户,允许该用户在没有root权限的情况下对其进行管理。
将数据分成逻辑组可以更容易地使用这些ZFS功能来支持组织。
数据集的属性可以继承到子数据集。
数据集之间移动文件实际是复制然后删除,比传统文件系统中移动文件要消耗更多时间。
使用zfs list命令查看所有数据集:
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
mypool 420M 17.9G 96K none
mypool/ROOT 418M 17.9G 96K none
mypool/ROOT/default 418M 17.9G 418M /
...
如果指定数据集,zfs list命令将列出指定数据集的信息:
xxxxxxxxxx
# zfs list mypool/lamb
NAME USED AVAIL REFER MOUNTPOINT
mypool/lamb 192K 17.9G 96K /lamb
-t选项则显示特定的数据集类型(filesystem/volume/snapshot),比如:
xxxxxxxxxx
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/var/log/db@backup 0 - 10.0G -
使用zfs create命令创建数据集。
文件系统是最常见的数据集类型。
xxxxxxxxxx
# zfs create mypool/lamb
# mount | grep lamb
mypool/lamb on /lamb (zfs, local, noatime, nfsv4acls)
以上命令在池mypool中创建一个新的数据集lamb。如果池有默认的挂载点,那么新数据集将默认挂载。
括号中的装载设置通常是从父数据集继承的ZFS属性。
要创建子文件系统,需要提供父文件系统的完整路径:
xxxxxxxxxx
# zfs create mypool/lamb/baby
在zfs create命令中使用-V选项和卷大小创建卷。同样需要提供卷数据集的完整路径:
xxxxxxxxxx
# zfs create -V 4G mypool/avolume
# zfs list mypool/avolume
NAME USED AVAIL REFER MOUNTPOINT
mypool/avolume 4.13G 17.9G 64K -
zvols自动保留的空间量等于卷的大小加上ZFS元数据,这个4GB的zvol使用了4.13GB的空间。
作为块设备,zvol没有挂载点,只是在/dev/zvol下获得了一个设备节点,因此可以像访问其他任何块设备一样访问它。
xxxxxxxxxx
# ls -al /dev/zvol/mypool/avolume
crw-r----- 1 root operator 0x4d Mar 27 20:22 /dev/zvol/mypool/avolume
可以在这个设备点上用newfs命令、向其复制磁盘映像,并像使用其他块设备一样使用它。
使用zfs rename命令可以修改数据集的名称:
xxxxxxxxxx
# zfs rename db/production db/old
# zfs rename db/testing db/production
如果数据集正在使用中,可以使用-f参数可强制执行这个命令。
利用 zfs rename命令可以将数据集从一个ZFS树中移动到另一个ZFS树,是数据集成为其新父级的子集。这可能会导致数据集的许多基于继承关系的属性发生变化,而数据集上专门设置的属性不会发生变化。
xxxxxxxxxx
# zfs rename zroot/var/db/mysql zroot/important/mysql
注意,如果挂载点是继承的,这可能会改变数据集的挂载点。如果使用-u参数,则可以不立即更改挂载点。但重启系统会使新挂载点生效。
可以重命名快照,但不能将快照移出其父数据集。
xxxxxxxxxx
# zfs destroy db/old
使用-r选项可以递归销毁数据集的所有子项(数据集、快照等)。
使用-R选项会销毁任何克隆的数据集。
使用-v和-n选项可以查看销毁数据集时会发生什么。
-v显示关于被销毁内容的详细信息。
-n则执行一次干运行。(不实际运行,仅显示运行后的效果)
ZFS属性用于控制数据集的工作方式。有些属性是在创建数据集时才能设置的,有些是在数据集运行时可以调整的。
ZFS还提供了许多只读属性,比如数据集消耗的空间量、压缩或去重率、数据集的创建时间等等。
ZFS的属性有:
xThe following properties are supported:
PROPERTY EDIT INHERIT VALUES
available NO NO <size>
clones NO NO <dataset>[,...]
compressratio NO NO <1.00x or higher if compressed>
createtxg NO NO <uint64>
creation NO NO <date>
defer_destroy NO NO yes | no
encryptionroot NO NO <filesystem | volume>
filesystem_count NO NO <count>
guid NO NO <uint64>
keystatus NO NO none | unavailable | available
logicalreferenced NO NO <size>
logicalused NO NO <size>
mounted NO NO yes | no
objsetid NO NO <uint64>
origin NO NO <snapshot>
receive_resume_token NO NO <string token>
redact_snaps NO NO <snapshot>[,...]
refcompressratio NO NO <1.00x or higher if compressed>
referenced NO NO <size>
snapshot_count NO NO <count>
snapshots_changed NO NO <date>
type NO NO filesystem | volume | snapshot | bookmark
used NO NO <size>
usedbychildren NO NO <size>
usedbydataset NO NO <size>
usedbyrefreservation NO NO <size>
usedbysnapshots NO NO <size>
userrefs NO NO <count>
written NO NO <size>
aclinherit YES YES discard | noallow | restricted | passthrough | passthrough-x
aclmode YES YES discard | groupmask | passthrough | restricted
acltype YES YES off | nfsv4 | posix
atime YES YES on | off
canmount YES NO on | off | noauto
casesensitivity NO YES sensitive | insensitive | mixed
checksum YES YES on | off | fletcher2 | fletcher4 | sha256 | sha512 | skein | edonr | blake3
compression YES YES on | off | lzjb | gzip | gzip-[1-9] | zle | lz4 | zstd | zstd-[1-19] | zstd-fast | zstd-fast-[1-10,20,30,40,50,60,70,80,90,100,500,1000]
context YES NO <selinux context>
copies YES YES 1 | 2 | 3
dedup YES YES on | off | verify | sha256[,verify] | sha512[,verify] | skein[,verify] | edonr,verify | blake3[,verify]
defcontext YES NO <selinux defcontext>
devices YES YES on | off
dnodesize YES YES legacy | auto | 1k | 2k | 4k | 8k | 16k
encryption NO YES on | off | aes-128-ccm | aes-192-ccm | aes-256-ccm | aes-128-gcm | aes-192-gcm | aes-256-gcm
exec YES YES on | off
filesystem_limit YES NO <count> | none
fscontext YES NO <selinux fscontext>
jailed YES YES on | off
keyformat NO NO none | raw | hex | passphrase
keylocation YES NO prompt | <file URI> | <https URL> | <http URL>
logbias YES YES latency | throughput
mlslabel YES YES <sensitivity label>
mountpoint YES YES <path> | legacy | none
nbmand YES YES on | off
normalization NO YES none | formC | formD | formKC | formKD
overlay YES YES on | off
pbkdf2iters NO NO <iters>
prefetch YES YES none | metadata | all
primarycache YES YES all | none | metadata
quota YES NO <size> | none
readonly YES YES on | off
recordsize YES YES 512 to 1M, power of 2
redundant_metadata YES YES all | most | some | none
refquota YES NO <size> | none
refreservation YES NO <size> | none
relatime YES YES on | off
reservation YES NO <size> | none
rootcontext YES NO <selinux rootcontext>
secondarycache YES YES all | none | metadata
setuid YES YES on | off
sharenfs YES YES on | off | NFS share options
sharesmb YES YES on | off | SMB share options
snapdev YES YES hidden | visible
snapdir YES YES hidden | visible
snapshot_limit YES NO <count> | none
special_small_blocks YES YES zero or 512 to 1M, power of 2
sync YES YES standard | always | disabled
utf8only NO YES on | off
version YES NO 1 | 2 | 3 | 4 | 5 | current
volblocksize NO YES 512 to 128k, power of 2
volmode YES YES default | full | geom | dev | none
volsize YES NO <size>
vscan YES YES on | off
xattr YES YES on | off | dir | sa
userused@... NO NO <size>
groupused@... NO NO <size>
projectused@... NO NO <size>
userobjused@... NO NO <size>
groupobjused@... NO NO <size>
projectobjused@... NO NO <size>
userquota@... YES NO <size> | none
groupquota@... YES NO <size> | none
projectquota@... YES NO <size> | none
userobjquota@... YES NO <size> | none
groupobjquota@... YES NO <size> | none
projectobjquota@... YES NO <size> | none
written@<snap> NO NO <size>
written#<bookmark> NO NO <size>
Sizes are specified in bytes with standard units such as K, M, G, etc.
User-defined properties can be specified by using a name containing a colon (:).
The {user|group|project}[obj]{used|quota}@ properties must be appended with
a user|group|project specifier of one of these forms:
POSIX name (eg: "matt")
POSIX id (eg: "126829")
SMB name@domain (eg: "matt@sun")
SMB SID (eg: "S-1-234-567-89")
zfs get命令可以查看数据集属性:
xxxxxxxxxx
# zfs get compression mypool/lamb
NAME PROPERTY VALUE SOURCE
mypool/lamb compression lz4 inherited from mypool
SOURCE有四种情况:
default表示使用了默认属性;
local表示有人设置了此数据集自己的属性;
temporary表示当前数据集挂载时使用了临时属性,卸载后将恢复为正常值;
inherited表示从其父数据集继承的属性。
有些属性没有来源,因为来源要么无关紧要,要么本质上显而易见。
记录数据集创建日期和时间的creation属性就没有来源,因为该值来自当时的系统时钟。
使用all选项可以获取所有属性,而如果同时未指定数据集,则显示所有数据集的所有属性。
要想获取某几个属性,可以按以下方式操作:
xxxxxxxxxx
# zfs get quota,reservation zroot/home
NAME PROPERTY VALUE SOURCE
zroot/home quota none local
zroot/home reservation none default
也可以使用zfs list命令的-o选项来查看属性,当想从多个数据集中查看多个属性时,这最合适。
xxxxxxxxxx
# zfs list -o name,quota,reservation
NAME QUOTA RESERV
db none none
zroot none none
zroot/ROOT none none
zroot/ROOT/default none none
...
zroot/var/log 100G 20G
...
也可以指定数据集名称,查看该数据集的某些属性。例如:
xxxxxxxxxx
# zfs list -o name,quota,reservation,creation zroot/old
NAME PROPERTY VALUE SOURCE
zroot/old name zroot/old -
zroot/old quota none default
zroot/old reservation none default
zroot/old creation Wed Aug 14 10:23 2024 -
# zfs get name,quota,reservation,creation zroot/old
NAME PROPERTY VALUE SOURCE
zroot/old name zroot/old -
zroot/old quota none default
zroot/old reservation none default
zroot/old creation Wed Aug 14 10:23 2024 -
使用zfs set命令修改属性:
xxxxxxxxxx
# zfs set compression=off mypool/lamb/baby
# zfs get compression mypool/lamb/baby
NAME PROPERTY VALUE SOURCE
mypool/lamb/baby compression off local
大多数情况下,变更属性仅影响修改属性后写入的数据,而不会影响数据集中已有的数据。
要想让所有数据都套用新的属性,最好的方法是创建新的数据集,设置好数据集属性后,用zfs send明了复制数据,然后销毁原始数据集。
某些属性为只读,用于提供有关数据集的基本信息,无法更改。
管理传统文件系统性能和行为的一个关键工具是挂载选项。可以以只读方式挂载传统文件系统,也可以使用noexec标志禁用运行其中的程序。
ZFS使用属性来实现相同的效果。
ZFS的atime属性控制数据集是否跟踪访问时间。
默认为on,每次访问文件时都会更新文件的atime元数据。
使用atime意味着每次读取磁盘时都要写入磁盘。
关闭此属性可以避免在读取文件时写入磁盘,并可以显著提高性能。但可能会影响依赖文件读取时间的程序,比如邮件程序等。
启用atime会增加快照大小。
exec属性决定是否有人可以在此文件系统上运行二进制文件和命令。
默认为on,允许执行。
将exec属性设置为off可以禁止用户从此数据集运行程序。
但是exec属性并不禁止运行解释性脚本。如果用户可以运行/bin/sh,那他也可以运行/bin/sh /home/mydir/script.sh。因为只是从脚本中获取指令。
如果不希望向此数据集写入任何内容,可以将readonly属性设置为on。
默认值为off。
setuid程序又风险,默认情况下,zroot/tmp、zroot/usr/ports、zroot/usr/src、zroot/var/audit、zroot/var/crash、zroot/var/log、zroot/var/tmp这些数据集的setuid是禁用的(off)。
自定义属性有利于开发全新的自动化程序。且子数据集可以自动继承这些自定义的属性。
为了避免冲突,应创建一个命名规则。大多数人在自定义属性前面加上组织标识符和冒号。
例如,FreeBSD特定的属性具有"org.FreeBSD:propertyname"的格式,形如org.FreeBSD:swap。
较真实的实例,zfstools工具使用特定的属性来实现快照:
xxxxxxxxxx
Message from zfstools-0.3.6_2:
--
To enable automatic snapshots, place lines such as these into /etc/crontab:
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
15,30,45 * * * * root /usr/local/sbin/zfs-auto-snapshot frequent 4
0 * * * * root /usr/local/sbin/zfs-auto-snapshot hourly 24
7 0 * * * root /usr/local/sbin/zfs-auto-snapshot daily 7
14 0 * * 7 root /usr/local/sbin/zfs-auto-snapshot weekly 4
28 0 1 * * root /usr/local/sbin/zfs-auto-snapshot monthly 12
This will keep 4 15-minutely snapshots, 24 hourly snapshots, 7 daily snapshots,
4 weekly snapshots and 12 monthly snapshots. Any resulting zero-sized snapshots
will be automatically cleaned up.
Enable snapshotting on a dataset or top-level pool with:
zfs set com.sun:auto-snapshot=true DATASET
Children datasets can be disabled for snapshot with:
zfs set com.sun:auto-snapshot=false DATASET
Or for specific intervals:
zfs set com.sun:auto-snapshot:frequent=false DATASET
See website and command usage output for further details.
数据集继承其父数据集的属性。在数据集上设置属性时,该属性将应用于其下所有子数据集。
为方便起见,可以通过-r选项在数据集及其所有子数据集上运行zfs命令。例如:
xxxxxxxxxx
# zfs get -r compression mypool/lamb
NAME PROPERTY VALUE SOURCE
mypool/lamb compression lz4 inherited from mypool
mypool/lamb/baby compression off local
通过SOURCE值可知,第一个数据集mypool/lamb从父池继承了compression属性。
第二个数据集mypool/lamb/baby则是设置了自己的compression属性。
以下操作恢复数据集的属性继承:
xxxxxxxxxx
# zfs inherit compression mypool/lamb/baby
# zfs get -r compression mypool/lamb
NAME PROPERTY VALUE SOURCE
mypool/lamb compression lz4 inherited from mypool
mypool/lamb/baby compression lz4 inherited from mypool
当更改了父级属性时,新属性会自动向下传播到子级:
xxxxxxxxxx
# zfs set compression=gzip-9 mypool/lamb
# zfs get -r compression mypool/lamb
NAME PROPERTY VALUE SOURCE
mypool/lamb compression gzip-9 local
mypool/lamb/baby compression gzip-9 inherited from mypool/lamb
若移动或重命名数据集而使其具有新的父级时,父级的属性会自动向下传播到子级。
local来源的属性保持不变,inherited属性则会切换到新父级的属性。
接上一个例子,mypool/lamb/baby的compression属性值为gzip-9,将其重命名到mypool/second下面之后,其compression属性值自动变更为lz4,因为它的compression属性是继承自父数据集的。
xxxxxxxxxx
# zfs create mypool/second
# zfs get compress mypool/second
NAME PROPERTY VALUE SOURCE
mypool/second compression lz4 inherited from mypool
# zfs rename mypool/lamb/baby mypool/second/baby
# zfs get -r compression mypool/second
NAME PROPERTY VALUE SOURCE
mypool/second compression lz4 inherited from mypool
mypool/second/baby compression lz4 inherited from mypool
这种情况下,baby数据集上数据有点混乱。在启用压缩之前写入的数据是未压缩的,当数据集使用gzip-9压缩时写入的数据用gzip-9进行压缩。现在写入的任何数据都将使用lz4进行压缩。虽然ZFS会自动解决这些问题,但确实会让强迫症头疼。
使用以下命令移除自定义属性:
xxxxxxxxxx
# zfs inherit com.allanjude:backup_ignore mypool/lamb
使用以下命令可以将数据集及其所有子数据集的属性重置为默认值,或完全删除自定义属性:
xxxxxxxxxx
# zfs inherit -r compression mypool
对于传统的文件系统,可以在/etc/fstab中列出每个分区、其类型以及应挂载的位置。甚至列出如软盘、光盘等。
由于ZFS允许创建大量文件系统,在/etc/fstab中列出每个文件系统变得不现实。
每个ZFS文件系统都有一个mountpoint属性来定义其挂载点。
默认的mountpoint来自池的mountpoint。如果池没有设置挂载点,就必须为数据集分配一个挂载点。
xxxxxxxxxx
# zfs get mountpoint zroot/usr/home
NAME PROPERTY VALUE SOURCE
zroot/usr/home mountpoint /usr/home inherited from zroot/usr
除了具有根文件系统的池之外的任何池,通常有一个以池名称命名的挂载点。例如,创建了名为db的池,则它的挂载点为/db,在它下面创建的数据集将继承这个挂载点。
当更改文件系统的mountpoint属性时,该文件系统和继承装载点的任何子文件系统将被卸载。如果新值是legacy,则保持卸载状态。否则,如果属性以前是legacy或none,或者如果它们是在属性更改之前转载的,则它们会自动装载到新位置。
另外,任何共享的文件系统将停止共享,并在新位置共享。
与普通文件系统一样,ZFS文件系统不一定被挂载。canmount属性控制文件系统的挂载行为。如果canmount设置为yes,则运行zfs mount -a命令会挂载文件系统。就像mount -a命令一样。
在/etc/rc.conf中设置了zfs_enable="YES",则FreeBSD会在启动时运行zfs mount -a以挂载所有canmount属性为yes的ZFS文件系统。
如果canmount设置为noauto,数据集只能被明确地挂载和卸载。 在数据集创建或导入时不会被自动挂载。 即不会由zfs mount -a命令挂载,也不会由zfs unmount -a卸载。 zroot/ROOT/default的canmount属性为noauto。
当canmount设置为off时,事情会变得有趣。 可以创建两个具有相同挂载点地不可挂载数据集。一个数据集可以仅仅为了未来数据集地父数据集而存在,但实际上并不能存储文件。 zroot/usr、zroot/var的canmount属性为off。
子数据集不继承canmount属性。
更改canmount属性不会自动卸载或装载文件系统。如果在已挂载地文件系统上禁用挂载,则需要手动卸载文件系统或重启系统。
ZFS数据集是分层的。可能需要创建一个永远不会只包含任何文件的数据集,这样它就可以成为许多其他数据集的公共父级。
xxxxxxxxxx
# zfs mount
zroot/ROOT/default /
zroot/tmp /tmp
zroot/usr/home /usr/home
zroot/usr/ports /usr/ports
zroot/usr/src /usr/src
...
我们在/usr下有各种各样的数据集,但没有挂载/usr数据集。
使用以下命令检查canmount和mountpoint:
xxxxxxxxxx
# zfs list -o name,canmount,mountpoint -r zroot/usr
NAME CANMOUNT MOUNTPOINT
zroot/usr off /usr
zroot/usr/home on /usr/home
zroot/usr/ports on /usr/ports
zroot/usr/src on /usr/src
由于zroot/usr的canmount属性为off,表示此数据集从未被挂载。所有写入/usr目录的文件(例如/usr/bin中的命令和/usr/local中的软件包)会进入root文件系统。低级别的挂载点(例如/usr/src)有自己的数据集和挂载点。
该数据集仅作为子数据集的父数据集而存在。/var分区也是类似情况。
将canmount设置为off允许数据集仅用作继承属性的机制。
将canmount设置为off的一个原因是有两个具有相同挂载点的数据集,这两个数据集的子数据集就会出现在同一个目录中,但可能具有不同的继承特征。
FreeBSD安装程序没有为默认池zroot设置mountpoint。创建新数据集时需要指定挂载点。
如果你不想为在池下创建的每个数据集分配一个挂载点,你可以将/的挂载点分配给zroot池,并将canmount设置为关闭。这样,当你创建一个新数据集时,它有一个要继承的挂载点。这是一个使用具有相同挂载点的多个数据集的非常简单的例子。
想象一下,你想要一个包含两组子目录的/opt目录。其中一些目录包含程序,安装后不应写入;其他目录包含数据。你必须锁定在文件系统级别运行程序的能力。
xxxxxxxxxx
# zfs create db/programs
# zfs create db/data
现在给这两个数据集赋予/opt的挂载点,并设置不能挂载:
xxxxxxxxxx
# zfs set canmount=off db/programs
# zfs set mountpoint=/opt db/programs
安装软件到数据集,然后设置其为只读:
xxxxxxxxxx
# zfs set readonly=on db/programs
不能从db/data数据集运行软件,所以关闭exec和setuid。但可以写数据:
xxxxxxxxxx
# zfs set canmount=off db/data
# zfs set mountpoint=/opt db/data
# zfs set setuid=off db/data
# zfs set exec=off db/data
现在创建一些子数据集,db/programs数据集的子级继承该数据集的属性,而db/data数据集的子集则继承另一组属性:
xxxxxxxxxx
# zfs create db/programs/bin
# zfs create db/programs/sbin
# zfs create db/data/test
# zfs create db/data/production
我们现在在/opt中挂载了四个数据集,其中两个用于二进制文件,两个用于数据。
目前不知道如何使用此功能。
池通常挂载在以池命名的目录中,但以下操作可以产生一个例外:
xxxxxxxxxx
# zfs set mountpoint=none mypool
这个池将不再被挂载。除非指定挂载点,否则池上的任何数据集都不会挂载。
xxxxxxxxxx
# zfs set mountpoint=/someplace mypool/lamb
如有必要,将创建目录并挂载文件系统。
使用zfs mount挂载文件系统。这常用于canmount设置为noauto的文件系统。
xxxxxxxxxx
# zfs mount mypool/usr/src
使用zfs unmount目录卸载文件系统即其所有子系统:
xxxxxxxxxx
# zfs unmount mypool/second
如果要在其他位置临时挂载数据集,可以使用-o选项指定新的挂载点:
xxxxxxxxxx
# zfs mount -o mountpoint=/mnt mypool/lamb
只能挂载定义了挂载点的数据集。当数据集没有挂载点时定义临时挂载点将会导致错误。
可以使用/etc/fstab管理某些或全部ZFS文件系统。将数据集的mountpoint属性设置为legacy(这将卸载文件系统):
xxxxxxxxxx
# zfs set mountpoint=legacy mypool/second
现在可以使用mount命令挂载这个数据集:
xxxxxxxxxx
# mount -t zfs mypool/second /tmp/second
也可以将ZFS数据集加入到/etc/fstab中。使用完整的数据集名称作为设备点。设置类型为zfs。可以使用标准的文件系统选择noatime、noexec、readonly、ro、nosuid。还可以明确地给出atime、exec、rw和suid地默认行为。
以下示例将scratch/junk挂载到/tmp:
xxxxxxxxxx
scratch/junk /tmp nosuid 2 0
但强烈建议使用ZFS属性来管理挂载。
zvols非常简单——这里有一块空间作为块设备,使用它。
可以调整卷使用空间地方式以及它提供的设备节点类型。
zvol的volsize属性指定卷的逻辑大小。默认情况下,创建卷会为数据集保留与卷大小相等的空间量。
更加volsize会更改预留。volsize只能设置为volblocksize属性的倍数,不能为零。
如果没有预留,卷可能会耗尽空间,导致未定义的行为或数据损坏,具体取决于卷的使用方式。当体积大小在使用过程中发生变化时,也会出现影响,特别时在缩小尺寸时。调整卷大小可能会混淆使用块设备的应用程序。
zvols还支持稀疏卷(sparse volumes),也称精简资源调配(thin provisioning)。
稀疏卷是指保留量小于卷大小的卷。从本质上讲,使用稀疏卷可以分配比数据集可用的空间更多的空间。
通过稀疏资源调配,可以在5TB的数据集上创建10个1TB的稀疏卷。只要卷未被大量使用。
不建议使用稀疏卷。即使卷本身看起来只是部分满,写入稀疏卷也可能会失败,并出现“空间不足”错误。
通过在zfs create -V命令中指定-s选项,在创建是指定稀疏卷。预定中不会反映卷的变化。
FreeBSD通常将zvols作为geom提供者暴露给操作系统,赋予它们最大的灵活性。可以使用volmode属性更改此设置。
将卷的volmode设置为dev只会讲卷作为/dev中的字符设备公开。此类卷只能作为原始磁盘设备文件访问。它们不能被分区或挂载,也不能参与RAID或其他GEOM功能。它们更快,在某些情况下,如果不信任使用卷的设备,dev模式可能更安全。
将volmode设置为none意味着卷不会暴露在ZFS之外。但这些卷可以快照、克隆和复制。这些卷可能适用于备份的目的。
将volmode设置为default意味着卷暴露有sysctl vfs.zfs.vol.mode控制。可以在系统范围内设置默认的zvol模式。值1表示默认值为geom,2表示dev,3表示none。
虽然可以更改活动卷的属性,但它没有任何效果。此属性仅在卷创建和池导入期间处理。
可以通过适用zfs rename命令来重建zvol设备。
ZFS的大多数保护都在VDEV层工作。毕竟,这就是块和磁盘变坏的地方。然而,一些硬件限制了池冗余。很少有笔记本电脑有足够的硬盘来使用镜像,更不用说RAID-Z了。但是,您可以在数据集层做一些事情,通过使用校验和、元数据冗余和副本来提供一些冗余。大多数用户永远用不到前两个,拥有冗余虚拟设备的用户可能希望不去碰这三个。
ZFS计算并存储它写入的每个块的校验和。这确保了当一个块被读回时,ZFS可以验证它与写入时相同,并且没有以某种方式被静默损坏。checksum属性控制数据集使用哪种校验和算法。有效设置包括on、fletcher2、fletcher4、sha256、off和noparity。
默认值为on,使用OpenZFS开发人员选择的算法,2015年,该算法是fletcher4。 标准算法fletcher4足够好用,且速度很快。如果想永远使用fletcher4,可以将此属性值设置为fletcher4。但建议保持默认的on,并在适当的时候让ZFS升级池的校验和算法。 ZFS的旧版本使用fletcher2。 sha256算法比fletcher4慢,但不太可能导致冲突(collision),多数情况下冲突是无害的。在执行去重时,经常建议使用sha256算法。
off会禁用对用户数据的完整性检查。
noparity不仅禁用完整性,还禁用维护用户数据的奇偶检验。此设置由驻留在RAID-Z池上的转储设备在内部使用,不应该被任何其他数据集使用。
ZFS存储两到三个重要元数据的副本,并可以对重要用户数据进行相同的处理。
copies属性告诉ZFS要保留多少个用户数据副本。ZFS会尝试将这些副本保存到不同的磁盘上。如果没有多余的磁盘,则保存在同一磁盘上尽量远的物理位置,以防止硬件故障。copies属性默认值为1,最大值为3。
如果一个池是由两个硬盘组成的镜像,copies设置为3,则数据会有6个副本。其中一个应该能在极端情况下幸存下来。
增加(increasing)或减少(decreasing)副本只会影响设置更改后写入的数据。将copies从1改为2,不会立即创建所有数据的重复副本。
以下示例创建10MB的随机数据:
xxxxxxxxxx
# dd if=/dev/random of=/lamb/random1 bs=1m count=10
10+0 records in
10+0 records out
10485760 bytes transferred in 0.144787 secs (72421935 bytes/sec)
# zfs set copies=2 mypool/lamb
现在每个块都存储两次。如果其中一个副本损坏,ZFS仍能读取文件。它知道哪些块已经损坏,因为它的校验和不匹配。但是看看池上的空间使用情况(REFER值):
xxxxxxxxxx
# zfs list mypool/lamb
NAME USED AVAIL REFER MOUNTPOINT
mypool/lamb 10.2M 13.7G 10.1M /lamb
只使用了我们写入的10MB。由于在更改copies属性之前编写了此文件,因此没有对其进行额外的复制。
然而,当copies设置为2时,如果写入另一个文件或覆盖原始文件,我们将看到不同的磁盘使用情况。
xxxxxxxxxx
# dd if=/dev/random of=/lamb/random2 bs=1m count=10
10+0 records in
10+0 records out
10485760 bytes transferred in 0.141795 secs (73950181 bytes/sec)
现在看看磁盘用量:
xxxxxxxxxx
# zfs list mypool/lamb
NAME USED AVAIL REFER MOUNTPOINT
mypool/lamb 30.2M 13.7G 30.1M /lamb
总空间使用量为30MB,10MB是第一个10MB文件的随机数据,20MB是第二个10MB文件的2个副本。
当我们用ls查看文件时,它们只显示实际大小:
xxxxxxxxxx
# ls -l /lamb/random*
-rw-r--r-- 1 root wheel 10485760 Apr 6 15:27 /lamb/random1
-rw-r--r-- 1 root wheel 10485760 Apr 6 15:29 /lamb/random2
如果真的想破坏数据集的弹性,可以看看元数据冗余。
每个数据集都存储了其内部元数据的额外副本,因此,如果单个块损坏,丢失的用户数据量是有限的。此额外副本是VDEV级别提供的任何冗余(例如通过镜像或RAID-Z)。
它也是copies属性指定的任何额外副本的补充,最多三份。
redundant_metadata属性运行决定数据集的冗余程度。大多数用户永远不应该更改此属性。
redundant_metadata属性的默认值为all,ZFS存储所有元数据的额外副本。如果磁盘上的单个块损坏,最坏的情况是,单个用户数据块可能会丢失。
如果将redundant_metadata属性设置为most,ZFS仅存储大多数类型元数据的额外副本。这可以提高随机写入的性能,因为必须写入的元数据更少。当只有大多数元数据是冗余的时,如果磁盘上的单个块损坏,最多可能会丢失大约100个用户数据块。冗余存储元数据块的确切行为可能会在未来的版本中发生变化。
如果将redundant_metadata属性设置为most,且copies属性为3,而数据集位于一个镜像池内。则ZFS存储大多数元数据的六个副本、数据和一些元数据的四个副本。
此属性是为经常更新元数据的特定用例(如数据库)而设计的。如果数据已经受到足够强的容错保护,减少每次数据库更改时必须写入的元数据副本数量可以提高性能。只有当你知道自己在做什么时,才能更改此值。