本章涵盖了其他地方不太适合的小主题。
将存储组合到池中是ZFS的核心功能之一。但ZFS也允许进行反向操作——将镜像池拆分为多个相同的池。
以下示例演示向镜像池中添加磁盘,然后将池拆分为多个副本。
建议在每个镜像VDEV中始终至少维持两个提供者。
镜像的深度描述了镜像包含的数据副本数量。
以下池是一个典型的条带镜像,包含两个镜像,每个镜像有两个磁盘:
# zpool status db
…
NAME STATE READ WRITE CKSUM
db ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
gpt/zfs0 ONLINE 0 0 0
gpt/zfs1 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
gpt/zfs2 ONLINE 0 0 0
gpt/zfs3 ONLINE 0 0 0
…
我们可以为每个VDEV添加一个额外的磁盘,使池变得更深。
使用zpool attach命令,加上池名称、目标VDEV中已有的设备和新的设备:
xxxxxxxxxx
# zpool attach db gpt/zfs1 gpt/zfs4
# zpool attach db gpt/zfs3 gpt/zfs5
在运行这两个命令之间,池的两个镜像中,一个镜像有三个设备、另一个镜像有两个设备。
最后,镜像看起来是这样的:
xxxxxxxxxx
NAME STATE READ WRITE CKSUM
db ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
gpt/zfs0 ONLINE 0 0 0
gpt/zfs1 ONLINE 0 0 0
gpt/zfs4 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
gpt/zfs2 ONLINE 0 0 0
gpt/zfs3 ONLINE 0 0 0
gpt/zfs5 ONLINE 0 0 0
当池完成数据同步后就可以分离池了。
使用zpool split命令从每个VDEV中提取设备一创建新池。
该命令需要两个必需参数:要拆分的池名称和新创建的池的名称。以下示例将db池拆出一个db2池,这两个池完全相同:
xxxxxxxxxx
# zpool split db db2
ZFS删除最近添加到每个镜像中的设备以创建新池。拆分池不会自动导入新池。导入后,分割池看起来像这样:
xxxxxxxxxx
# zpool status db2
…
NAME STATE READ WRITE CKSUM
db2 ONLINE 0 0 0
gpt/zfs4 ONLINE 0 0 0
gpt/zfs5 ONLINE 0 0 0
这个池包含两个条带化的磁盘。
在原始池中,条带化的一对三向镜像已经变成了条带化的一对双磁盘镜像。
如果要持续使用这个分离出来的池,应添加更多的磁盘以创建适当的镜像。如果分离出来的池仅仅是为了提取备份,则可能不需要添加另一组磁盘。
快照很棒,但它们像可能会肆意增长。一旦你习惯了使用快照来处理系统管理问题,你会发现自己因为拥有所有快照而面临磁盘空间短缺的问题。
删除单个快照很容易:
xxxxxxxxxx
# zfs destroy mypool/dataset@snapshotname
但按此方法销毁多个快照会及其繁琐。
可以使用snapspec识别多个相邻快照。虽然无法使用snapspec指定多个不同的快照,但可以按照一定的规律进行操作。
无论如何使用snapspec,都建议首先使用-n和-v运行命令。-v会显示运行命令的详细信息;-n则虚拟运行该命令。结合起来会在不影响实际数据的情况下观察可能出现的结果。
最基本的snapspec是 fromsnap%tosnap。它会销毁所指示的两个对象之间的每个快照,包括它们自己:
xxxxxxxxxx
# zfs destroy -vn mypool/dataset@one%three
would destroy mypool/dataset@one
would destroy mypool/dataset@two
would destroy mypool/dataset@three
如果@one和@three之间还有其他快照,比如@beforeupgrade,你会看到提示。这就是用-n的原因。
可以使用@%foo销毁@foo和比它更老的快照,使用@foo%销毁@foo和比它更新的快照。
xxxxxxxxxx
# zfs destroy -vn mypool/dataset@%four
would destroy mypool/dataset@one
would destroy mypool/dataset@two
would destroy mypool/dataset@three
would destroy mypool/dataset@four
xxxxxxxxxx
# zfs destroy -vn mypool/dataset@six%
would destroy mypool/dataset@six
would destroy mypool/dataset@seven
would destroy mypool/dataset@eight
would destroy mypool/dataset@nine
would destroy mypool/dataset@ten
这比重新输入每个快照名称要容易得多。
有时,你希望销毁所有快照。可使用@%:
xxxxxxxxxx
# zfs destroy -vn mypool/dataset@%
would destroy mypool/dataset@one
would destroy mypool/dataset@two
…
would destroy mypool/dataset@ten
现在,你可以重新开始累积快照了。
如果你拍摄了递归拍照,你可能像销毁整个快照树。添加-R选项以从数据集及其子数据集中删除快照。例如,我们完成了升级,并对结果感到满意,可以销毁所有以前的快照:
xxxxxxxxxx
# zfs destroy -nvR pgsql/data@%
would destroy pgsql/data@beforeupgrade
would destroy pgsql/data/base@beforeupgrade
would destroy pgsql/data/pg_xlog@beforeupgrade
但是,建议把备份多保留一段时间。
人生的高光时刻:等等,那个命令是一个可怕的错误。
你意识到了错误,但你那该死的右手小指已经按下了回车键。
一个可能发生的情况是销毁ZFS池。ZFS的设计者非常清楚这种综合症。
zpool destroy命令实际上不会损坏底层磁盘上的任何数据。相反,它将池标记为已被销毁。
zpool list命令会跳过标记为已销毁的池。如果尚未写入或物理移除已销毁的池的底层磁盘,那就可以恢复池。
使用zpool import -D命令可以查看已销毁的池:
xxxxxxxxxx
# zpool import -D
你可能收到两种响应,分别对应可恢复池和不可恢复池。
下面这个池可以很容易恢复:
xxxxxxxxxx
# zpool import -D
pool: db2
id: 5552158746006792385
state: ONLINE (DESTROYED)
action: The pool can be imported using its name or numeric identifier.
config:
db2 ONLINE
gpt/zfs4 ONLINE
gpt/zfs5 ONLINE
这个被销毁的池db2看起来像一个正常、健康的池。state行显示它是DESTROYED,但是输出信息显示了池中单个VDEV中的两个提供者,并且它们都在线。
要导入已销毁的池,可以在以上命令后面加上池名称:
xxxxxxxxxx
# zpool import -D db2
另一些销毁的池看起来像这样:
xxxxxxxxxx
# zpool import -D
pool: db
id: 13121127349626326109
state: UNAVAIL (DESTROYED)
status: One or more devices are missing from the system.
action: The pool cannot be imported. Attach the missing
devices and try again.
see: http://illumos.org/msg/ZFS-8000-6X
config:
db UNAVAIL missing device
mirror-1 DEGRADED
6883971156539624736 UNAVAIL cannot open
gpt/zfs3 ONLINE
Additional devices are known to be part of this pool, though their
exact configuration cannot be determined.
此例中state行显示为UNAVAIL,这意味着无法导入它。config中显示其中一个提供者也是UNAVAIL。ZFS找不到此池具有ZFS特定GUID的存储提供者。也许是你将该磁盘用在其他地方了,也许是把它从机箱拔出了。
这个例子中最令人烦恼的是什么?这个池是一个双盘镜像池。你有一份关于幸存提供者的数据的完美副本。但是池不完整,所以,无法导入它。根据action行的提示,需要找到那个丢失的盘,然后再试。
另一个常见的情况是,池中不再有SLOG设备。SLOG合适的硬件通常会直接在另一个池中重新使用或丢弃。使用zpool -m命令可以告诉zpool忽略丢失的SLOG并无论如何都导入池。
有时,当你在恢复销毁的池时,你像重命名它。也许它与当前活动的池同名,也许这个池的功能已经更改。要在导入池时重命名它,请在池的旧名称后面添加新名称:
xxxxxxxxxx
# zpool import -D db2 olddb2
在其他方面,这与重命名导入的池相同。
ZFS对于虚拟机来说时一个非常明智的选择。虽然失去对磁盘的直接访问意味着ZFS无法处理错误检测,但快照和复制等功能使ZFS变得有价值。
大多数虚拟化系统都提供了克隆服务,有时伪装成你可以部署的标准模板。但是,如果将包含ZFS池的磁盘映像复制到新的虚拟机,则你的虚拟机是原始虚拟机的副本。这意味着一些应该是全局唯一的项目不再是。不在独立的虚拟机上。但是,如果要在虚拟机之间移动磁盘映像,则需要更改每个VM池的GUID。
guid属性包含池的guid。这里我们得到池db2的GUID:
xxxxxxxxxx
# zpool get guid db2
NAME PROPERTY VALUE SOURCE
db2 guid 5552158746006792385 default
要生成新的池GUID,请使用zpool reguid。将池名称作为参数:
xxxxxxxxxx
# zpool reguid db2
# zpool get guid db2
NAME PROPERTY VALUE SOURCE
db2 guid 7662460469377566669 default
现在,您可以将磁盘映像从一个虚拟机附加到另一个虚拟机器,而不会使ZFS变得非常适合。
如果由于某种原因zdb(8)找不到您的池,为池提供一个新的GUID也会有所帮助。
有些客户端(特别是OS X)希望文件系统不区分大小写。可以更改数据集的casesensitivity属性。此属性的默认值是sensitive(敏感),这是类Unix风格的区分大小写属性。将其改为mixed(混合),ZFS可以支持区分大小写和不区分大小写的请求。若改为insensitive,ZFS将完全不区分大小写。
只能在创建数据集时设定该属性:
xxxxxxxxxx
# zfs create -o casesensitivity=mixed samba/share
要修改已有数据集的casesensitivity属性,就只能创建正确设置的属性创建新数据集,然后复制文件。
为了更好地了解ZFS内部发生的事情,能够窥探幕后是有帮助的。
检查ZFS的内部状态可以帮助你了解系统为什么以这种方式运行或表现。
FreeBSD中提供的ZFS工具套件包括zdb。
zdb手册页明确指出,此命令的输出通常反映了ZFS池的磁盘结构,并且本质上是不稳定的。大多数调用的精确输出没有记录,假设对ZFS内部有了解。“
输出基于磁盘上的内容和zdb对任何给定时刻内存中内容的模拟。
解释在很大程度上取决于操作员。
zdb命令有大量选项。所有这些都可以多次指定,每次都会增加信息的详细程度。
zdb实用程序可以检查块在池中的分配方式。我们将从虚拟机中检查一个非常小的池开始,然后检查越来越大的池。
使用-b选项和池名获取该池的块统计信息。
分析块统计信息需要大量内存,因为zdb在计算各种统计信息时必须跟踪每个块。一个非常大的池可能需要比主机更多的内存,最终内核的内存不足杀手会出于自卫而终止zdb。
在生产系统上运行此程序时要小心,因为zdb可能会使系统停止运行。
对于一个由三个8TB硬盘组成的RAID-Z1池,做一次zdb -b统计大概需要一个小时。
现在从虚拟机中的一个小型单磁盘池开始:
x# zdb -b mypool
Traversing all blocks to verify nothing leaked ...
925M completed ( 473MB/s) estimated time remaining: 0hr 00min 00sec
No leaks (block sum matches space maps exactly)
bp count: 85010
ganged count: 0
bp logical: 2159973376 avg: 25408
bp physical: 897291776 avg: 10555 compression: 2.41
bp allocated: 1159446528 avg: 13638 compression: 1.86
bp deduped: 0 ref>1: 0 deduplication: 1.00
SPA allocated: 1159446528 used: 5.72%
additional, non-pointer bps of type 0: 5873
Dittoed blocks on same vdev: 9645
统计数据的第一部分涵盖了块指针,即包含元数据和数据块索引详细信息的块。
以下是一个来自只有一个磁盘VDEV的活动服务器的稍大的池:
xxxxxxxxxx
bp count: 1877355
bp logical: 40057641984 avg: 21337
bp physical: 36864202240 avg: 19636 compression: 1.09
bp allocated: 40843472896 avg: 21755 compression: 0.98
bp deduped: 0 ref>1: 0 deduplication: 1.00
SPA allocated: 40843472896 used: 8.34%
这个池包含大量不可压缩的数据。bp physical条目显示,压缩系数为1.09。不过,再往下看分配的空间(bp allocated),实际上得到了0.98的压缩率。压缩几乎弥补了元数据造成的空间损失。
下面是一个来自四盘RAID-Z1的例子:
xxxxxxxxxx
bp count: 243197
ganged count: 0
bp logical: 15037198336 avg: 61831
bp physical: 10384008704 avg: 42697 compression: 1.45
bp allocated: 15081398272 avg: 62013 compression: 1.00
bp deduped: 0 ref>1: 0 deduplication: 1.00
SPA allocated: 15081398272 used: 0.19%
使用四盘RAID-Z1,你会损失25%的物理空间来实现奇偶检验。它有大约15GB的数据,但压缩会将其压缩到10GB。
不过看一下分配空间,压缩和RAID-Z元数据实际是相互抵消了。
下面是另一个四盘RAID-Z1,但数据更多:
xxxxxxxxxx
bp count: 8782753
bp logical: 845698973696 avg: 96290
bp physical: 838824515072 avg: 95508 compression: 1.01
bp allocated: 1173701099520 avg: 133637 compression: 0.72
bp deduped: 0 ref>1: 0 deduplication: 1.00
SPA allocated: 1173701099520 used: 29.70%
它存储了大约845GB的数据,但由于是RAID-Z1,所以它实际分配了超过1TB的空间。
(对于我实际的NAS系统,有一个三盘RAID-Z1池。8T的数据,实际分配(bp allocated)了11T的空间,压缩比只有0.69。)
如果上面的数字不够详细,可以再加上第二个-b获得更详细的块统计数据:
xxxxxxxxxx
# zdb –bb mypool
你会得到一个统计表,包含以下列:
xxxxxxxxxx
Blocks LSIZE PSIZE ASIZE avg comp %Total Type
9 68.0K 68.0K 68.0K 7.55K 1.00 0.01 ZIL intent log
70.3K 1.87G 844M 1.01G 14.7K 2.26 93.43 ZFS plain file
7.12K 9.6M 2.53M 24.7M 3.47K 3.78 2.23 ZFS directory
272 174K 38.0K 608K 2.23K 4.58 0.05 ZFS user/group used
244 315K 59.0K 1.38M 5.80K 5.34 0.13 DSL deadlist map
6 60.0K 11.0K 72.0K 12.0K 5.45 0.01 deferred free
8 66.0K 10.0K 84.0K 10.5K 6.60 0.01 other
…
83.0K 2.01G 856M 1.08G 13.3K 2.41 100.00 Total
最后一行给出了总数。这个池有大约83K个指针块,代表2.01GB的数据。此数据使用856MB的逻辑空间,但由于ZFS添加了填充和元数据,则需要1.08GB。
下面看看Type列出现的这些类型:
使用zdb -C命令可以查看系统的ZFS配置。比如以下示例显示media池的配置信息:
xxxxxxxxxx
# zdb -C media
MOS Configuration:
version: 5000
name: 'media'
state: 0
txg: 15612202
pool_guid: 16862785426161824963
hostid: 2655503804
hostname: ''
vdev_children: 1
vdev_tree:
type: 'root'
id: 0
guid: 16862785426161824963
create_txg: 4
这给出了media池的基本细节。其中一些信息相对明显,例如池的GUID和使用此池的主机的hostid。此池已提交15612202个事务组。vdev_children字段显示此池中有多少VDEV。
池VDEV信息以树状显示,列出每个VDEV,然后列出该VDEV中的磁盘。这是media池中的VDEV:
xxxxxxxxxx
children[0]:
type: 'raidz'
id: 0
guid: 8519167489302904218
nparity: 2
metaslab_array: 30
metaslab_shift: 37
ashift: 12
asize: 17990635487232
is_log: 0
create_txg: 4
VDEV中的每个磁盘都有一个条目:
xxxxxxxxxx
children[0]:
type: 'disk'
id: 0
guid: 14921375587032757624
path: '/dev/ada1p3'
phys_path: '/dev/ada1p3'
whole_disk: 1
DTL: 8495
create_txg: 4
这告诉您关于ZFS GUID、FreeBSD设备节点和一些内部。
在最底部,您将看到此池上的只读功能列表:
xxxxxxxxxx
features_for_read:
com.delphix:hole_birth
com.delphix:embedded_data
如果使用第二个-C和池名,zdb将检索磁盘上的数据和缓存的数据,以便进行比较。这些应该有所不同吗?不是真的。
详细检查数据集还可以提供大量信息,并有助于可视化文件系统的内部。
使用zdb -d加上数据集名称,可以查看指定数据集的内部结构信息:
xxxxxxxxxx
# zdb -d media/svn/base
Dataset media/svn/base [ZPL], ID 4778, cr_txg 4820082, 3.82G, 259339 objects
cr_txg字段显示了创建此数据集的事务组。它保存了3.82GB数据,其中有259339个对象。
对象包括目录和文件,还包括元数据、ACL和ZFS可以保存的所有其他类型的数据。
在以上命令上再加一个-d,可以得到更加详细的信息:
xxxxxxxxxx
# zdb -dd media/svn/base
Dataset media/svn/base [ZPL], ID 4778, cr_txg 4820082, 3.82G, 259339 objects
Object lvl iblk dblk dsize lsize %full type
0 7 16K 16K 417M 632M 20.04 DMU dnode
-1 1 16K 1K 0 1K 100.00 ZFS user/group used
-2 1 16K 1K 0 1K 100.00 ZFS user/group used
1 1 16K 1K 16K 1K 100.00 ZFS master node
2 1 16K 512 16K 512 100.00 SA master node
…
9 1 16K 16.5K 16K 16.5K 100.00 ZFS directory
11 3 16K 128K 43.3M 155M 82.49 ZFS plain file
13 1 16K 512 8K 512 100.00 ZFS plain file
…
这个数据集中有一大堆文件、目录和相关内容。
系统管理员可能会对其中一些列感兴趣,第一列是编号、dblk列是用于此对象的记录大小、lsize是对象的逻辑大小(这是我们大多数人在说“文件大小”时想到的)。
第一行提供了基本信息。接下来会看到数据集中每个对象的详细信息。
虽然前几个对象总是ZFS元数据,但后面的对象大多数是文件和目录。
数据集对象列表可能很有趣,但每个对象是什么?
通过在数据集名称后指定对象编号来检查对象。
xxxxxxxxxx
# zdb -ddddd media/svn/base 1294328
Dataset media/svn/base [ZPL], ID 4778, cr_txg 4820082, 3.82G, 259339 objects, rootbp DVA[0]=<0:bc346503000:3000> DVA[1]=<0:f005fc91000:3000> [L0 DMU objset] fletcher4 uncompressed LE contiguous unique double size=800L/800P birth=15618812L/15618812P fill=259339 cksum=1003e8933c:10304c47fe66:af75e77a47edd:5dcc1d2be9f01d9
我们从数据集的细节开始,比如创建txg和对象数量,就像我们在不太密集的zdb查询中看到的那样。我们还获得了更多的细节,比如当前的校验和以及其他只有在学习D&I时才有意义的东西。
然后我们得到一些关于文件本身的细节。
xxxxxxxxxx
Object lvl iblk dblk dsize lsize %full type
1294328 1 16K 4.50K 8K 4.50K 100.00 ZFS plain file
168 bonus System attributes
此文件的大小为4.50 KB,但数据大小(dsize)为8 KB,因为磁盘上的大小是整个扇区。 然后我们将进入文件的核心。
xxxxxxxxxx
dnode flags: USED_BYTES USERUSED_ACCOUNTED
dnode maxblkid: 0
path /head/sys/arm64/include/bus_dma_impl.h
uid 1001
gid 1001
atime Sat May 9 12:40:22 2015
mtime Sat May 9 12:40:22 2015
ctime Sat May 9 12:40:22 2015
crtime Sat May 9 12:40:22 2015
gen 10832525
mode 100644
size 4139
parent 1247454
links 1
pflags 40800000004
Indirect blocks:
0 L0 0:e1c09620000:3000 1200L/a00P F=1 B=10832525/10832525
segment [0000000000000000, 0000000000001200) size 4.50K
您将看到一堆传统的Unix信息:权限、文件名和路径、时间、父对象等。如果你用ls查看这个文件,它看起来是4139字节,但不包括任何支持它的ZFS元数据。
现在让我们考虑一个更大的lz4压缩文件。
xxxxxxxxxx
# zdb -ddddd zstore/tmp 3628
…
Object lvl iblk dblk dsize lsize %full type
3628 2 16K 128K 244K 896K 100.00 ZFS plain file
168 bonus System attributes
这从基本的池信息开始,然后深入到文件本身。虽然此文件占用244 KB的磁盘空间,但其实际大小为896 KB。压缩减少了所需的磁盘空间量。
不过,在Unix信息之后,我们会得到一个间接块列表。
xxxxxxxxxx
Indirect blocks:
0 L1 0:20edc2ec000:2000 4000L/1000P F=7 B=15965896/15965896
0 L0 0:188fc2c8000:c000 20000L/8000P F=1 B=15965895/15965895
20000 L0 0:188fc2f8000:c000 20000L/8000P F=1 B=15965895/15965895
40000 L0 0:188fc2ec000:c000 20000L/8000P F=1 B=15965895/15965895
60000 L0 0:188fc2e0000:c000 20000L/8000P F=1 B=15965895/15965895
80000 L0 0:188fc2d4000:c000 20000L/8000P F=1 B=15965895/15965895
a0000 L0 0:188fc324000:c000 20000L/8000P F=1 B=15965895/15965895
c0000 L0 0:20834cea000:8000 20000L/6000P F=1 B=15965896/15965896
segment [0000000000000000, 00000000000e0000) size 896K
当文件大于recordsize(dblk)时,ZFS将其存储为多个单独的块。第一列是文件中的偏移量,以十六进制表示。十六进制中的数字20000是128KB。所讨论的文件有一个L1间接块,然后是七个实际保存数据的128KB L0块,最后一个实际上稍小。
也许你想看看一个特定的文件——比如,看看它是用什么块大小写的。你不能轻易地从zdb–d中提取它,但你可以通过使用–i标志从ls(1)中获取序列号或索引节点号。在这里,出于某种难以形容的原因,我们对MySQL数据文件感兴趣。
xxxxxxxxxx
# ls -i /var/mysql/nyaargh/users.MYI
132 /var/mysql/nyaargh/users.MYI
这是zroot/var/mysql数据集上的文件132。
当使用inode编号工作时,用zdb -v查看此文件:
xxxxxxxxxx
# zdb -v zroot/var/mysql 132
Dataset zroot/var/mysql [ZPL], ID 128, cr_txg 18594, 293M, 534 objects
Object lvl iblk dblk dsize lsize %full type
132 1 16K 6.00K 8K 6.00K 100.00 ZFS plain file
使用四个或更多-v选项显示传统的Unix信息和间接块。
每个顶级虚拟设备都被分解为metaslabs。ZFS在metaslab-by-metaslab基础上填充空间。
在ZFS分配空间时,它会寻找足够大的磁盘块来容纳新事务。当你的池满了,写入数据时唯一的选择就是把它分成剩下的小块空间。则就会造成ZFS性能随着池的填满而降低——可用空间变得碎片化。使用以下命令查看metaslab有多满:
xxxxxxxxxx
# zdb -mmm media
Metaslabs:
vdev 0
metaslabs 130 offset spacemap free
-------------- ------------- --------------- -----------
metaslab 0 offset 0 spacemap 8317 free 4.72G
segments 806 maxsize 4.68G freepct 3%
每个metalab定义都以一个基本描述开始。这里我们看到VDEV 0,它有130个metalabs。然后我们继续对编号0的metalab进行处理。它就在池的开头,偏移量为0。该池有806个分配或分段,其中只有3%是可用的。
然后,就系统内存而言,我们得到了这个metalab中块分配的直方图:
xxxxxxxxxx
In-memory histogram:
13: 281 ****************************************
14: 197 *****************************
15: 189 ***************************
16: 106 ****************
17: 27 ****
18: 5 *
19: 0
20: 0
…
31: 0
32: 1 *
第一列中的数字是块大小,以2的幂表示为千字节。213=8192,所以13是8KB。此元实验室有281个8KB的分配。
第14行是16KB。此元实验室有197个16KB的分配。
第15行是32KB,有189个分配,以此类推,一直到一个232(或4GB)的分配。
在内存中的metaslab直方图之后,我们可以看到磁盘上metaslab的版本是什么样子的。在繁忙的磁盘上,ZFS始终在分配和取消分配块。
xxxxxxxxxx
On-disk histogram: fragmentation 0
13: 295 ****************************************
14: 198 ***************************
15: 189 **************************
16: 107 ***************
17: 29 ****
18: 3 *
…
32: 1 *
向下滚动。不,更进一步。最终,您将看到一个看起来大不相同的后期元实验室。在这种情况下是Metaslab 43。
xxxxxxxxxx
metaslab 43 offset 56000000000 spacemap 8280 free 59.1G
segments 17893 maxsize 815M freepct 46%
这个metalab有17893个分配,但46%是自由的。块大小分布也大不相同。
xxxxxxxxxx
In-memory histogram:
13: 891 *********
14: 565 ******
15: 806 ********
16: 994 **********
17: 3341 *******************************
18: 1452 **************
19: 1932 ******************
20: 4406 ****************************************
21: 1557 ***************
22: 934 *********
23: 488 *****
24: 272 ***
25: 103 *
26: 80 *
27: 47 *
28: 19 *
29: 6 *
我们最常见的分配是17(128 KB)和20(1 MB)。
不过,这个磁盘暗示了为什么这个元实验室只有大约一半的空间。
xxxxxxxxxx
On-disk histogram: fragmentation 11
13: 7520 ***********************
14: 5702 ******************
15: 4096 *************
…
注意碎片级别--11。在磁盘上,metaslab 43是碎片化的。这意味着许多自由空间块相对较小。通过旋转磁盘,连续存储文件块可以提高性能。如果ZFS需要编写一个大块,它可能会继续到稍后的metalab。
进一步深入你的metaslabs内部。
xxxxxxxxxx
metaslab 121 offset f2000000000 spacemap 0 free 128G
segments 1 maxsize 128G freepct 100%
In-memory histogram:
37: 1 *
磁盘末尾附近的metalab由连续的128 GB块组成。如果这个池以前几乎满了,编号较高的元实验室可能会包含一些数据,而在这个池上,它们是不受影响的。
ZFS通常将VDEV划分为200个大小相等的metalab。您可以使用vfs.zfs.vdev.metalabs_per_vdev sysctl调整此数字,但必须在创建vdev之前设置sysctl。之所以选择数字200,是因为它似乎运行得很好,但metalab分配还有很大的实验空间。
当您通过用更大的磁盘替换VDEV来扩展VDEV时,ZFS会创建新的metalab来支持增加的空间。通过这种方式,你可以得到一个拥有200多个metalab的池。 ZFS一次只能在内存中保留这么多metalab。将VDEV扩展到其原始大小的许多倍可能会对性能产生负面影响,因为ZFS会在磁盘之间来回移动metalab。
如果不查看池的uberblock,这将是什么样的ZFS调试部分?
xxxxxxxxxx
# zdb -u media
Uberblock:
magic = 0000000000bab10c
version = 5000
txg = 15741196
guid_sum = 7884957152936881795
timestamp = 1456030423 UTC = Sat Feb 20 23:53:43 2016
你能用这个做什么?不多。但在这一点上,ZFS几乎赤裸裸地躺在你面前。
你还能学到什么取决于你。