Z 文件系统最初是由 Sun™ 开发的, 它使用基于池的存储方法,只有存储数据时才会真正消耗空间。 它的设计也能够最大限度地保证数据完整性,并支持数据快照、多份副本以及数据校验。 它使用了一种被称为 RAID-Z 的软件实现的数据复写模型。 RAID-Z 能够提供类似于硬件 RAID 的冗余性, 能够防止数据写入时损坏,并克服了硬件 RAID 的一些限制。
ZFS 所提供的某些特性需要消耗大量内存, 因此在内存较少的系统上,我们要调整一些参数, 才能充分发挥其性能。
如果不考虑其他应用的开销,系统的总内存不应少于 1GB。 理想的内存大小取决于存储池的大小和启用了哪些 ZFS 特性。 通行的准则是:每 1TB 存储空间需要 1GB 内存。 如果启用了重复数据删除(deduplication)特性, 那么通行的准则是:每消去 1TB 存储空间,需要 5GB 内存。 尽管有些用户在内存不足的机器上也能成功使用 ZFS , 但是当负载较高时,系统极有可能由于内存耗尽而崩溃。
由于 i386™ 平台有内存限制, 在 i386™ 架构上使用 ZFS 的用户应当在内核配置文件中加入下列选项, 重新编译内核并重启机器:
options KVA_PAGES=512
这个选项可以扩展内核的地址空间,
使得 vm.kvm_size
能够突破 1 GB 的限制( PAE 为 2 GB )。
为了找出这个选项最合适的值,
以兆(MB)为单位把所需的地址空间除以 4 即可。
在本例中,2 GB 地址空间则设置为 512
。
在 FreeBSD 支持的所有架构上,都应该加大 kmem
地址空间。
我们在一台拥有 1 GB 物理内存的测试系统上,
通过修改 /boot/loader.conf
加入下列参数并且重启,
使其通过了测试。
vm.kmem_size="330M" vm.kmem_size_max="330M" vfs.zfs.arc_max="40M" vfs.zfs.vdev.cache.size="5M"
关于 ZFS 更详细的调校方法请参阅
http://wiki.freebsd.org/ZFSTuningGuide
。
FreeBSD 有一种启动机制能在系统初始化时挂载 ZFS 存储池。 可通过以下命令设置:
#
echo 'zfs_enable="YES"' >> /etc/rc.conf
#
/etc/rc.d/zfs start
接下来本节举一个例子,假定系统中有 3 块可用的 SCSI 磁盘,
它们的设备名分别为 da0
,
da1
和 da2
。
IDE 硬件的用户可以使用
ad
代替 da。
在单个磁盘上创建一个简单的,
非冗余的 ZFS 存储池,
使用 zpool
命令:
#
zpool create example /dev/da0
通过 df
命令的输出,
我们可以查看新建的存储池:
#
df
Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235230 1628718 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032846 48737598 2% /usr example 17547136 0 17547136 0% /example
这份输出显示 example
存储池不仅被创建成功而且被 挂载 了。
我们能像访问普通的文件系统那样访问它,
就像以下例子中演示的那样,用户能够在上面创建文件并浏览:
#
cd /example
#
ls
#
touch testfile
#
ls -al
total 4 drwxr-xr-x 2 root wheel 3 Aug 29 23:15 . drwxr-xr-x 21 root wheel 512 Aug 29 23:12 .. -rw-r--r-- 1 root wheel 0 Aug 29 23:15 testfile
可是这个存储池并没有用到任何 ZFS 特性。 我们可以在这个存储池上创建一个文件系统,并启用压缩:
#
zfs create example/compressed
#
zfs set compression=gzip example/compressed
现在 example/compressed
是一个启用了压缩的 ZFS 文件系统了。
我们可以尝试复制一些大的文件到 /example/compressed
。
如果要禁用压缩,可以使用如下命令:
#
zfs set compression=off example/compressed
如果要卸载这个文件系统,
则使用如下命令并用 df
命令确认:
#
zfs umount example/compressed
#
df
Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235232 1628716 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example
重新挂载这个文件系统,
并用 df
命令确认:
#
zfs mount example/compressed
#
df
Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235234 1628714 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example example/compressed 17547008 0 17547008 0% /example/compressed
我们也可使用 mount
命令来查看存储池与文件系统:
#
mount
/dev/ad0s1a on / (ufs, local) devfs on /dev (devfs, local) /dev/ad0s1d on /usr (ufs, local, soft-updates) example on /example (zfs, local) example/data on /example/data (zfs, local) example/compressed on /example/compressed (zfs, local)
ZFS 文件系统一旦创建,就能随意使用。
然而还有很多其他特性,能够在单个的文件系统上启用。
在下面的例子中,我们将创建一个名为 data
的文件系统。
我们将在这个文件系统上存储一些重要的文件,
并把它设置成为每一个数据块保存两份拷贝:
#
zfs create example/data
#
zfs set copies=2 example/data
让我们再次使用 df
命令查看数据和空间的使用状况:
#
df
Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235234 1628714 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example example/compressed 17547008 0 17547008 0% /example/compressed example/data 17547008 0 17547008 0% /example/data
请注意,同一个存储池上的所有文件系统都共享相同大小的可用空间。
这就是我们在上述例子中使用 df
命令的原因,
这样就能看出,这些文件系统都从同一个存储池获取了它们所需的空间。
ZFS 文件系统去掉了诸如卷和分区的概念,
并允许多个文件系统占用同一个存储池。
当不再需要文件系统与存储池的时候,用如下命令销毁它们:
#
zfs destroy example/compressed
#
zfs destroy example/data
#
zpool destroy example
磁盘不可避免地会坏掉和停止运转。 为了避免因磁盘损坏而丢失数据,有一种方法是实现 RAID。而 ZFS 在它的存储池设计中便支持这个特性。
假设存在 3 个
SCSI 设备,
da0
, da1
和 da2
,使用如下命令创建一个
RAID-Z 存储池:
#
zpool create storage raidz da0 da1 da2
Sun™ 推荐在一个 RAID-Z 配置中使用的磁盘数量为 3 至 9 块。 如果你要求在单独的一个存储池中使用 10 块或更多的磁盘, 请考虑分拆成更小 RAID-z 组。 如果你只有 2 块磁盘, 并仍然需要冗余, 请考虑使用 ZFS 的 mirror 特性。 更多细节请参考 zpool(8) 手册页。
zpool storage
至此就创建好了。
可以如前文提到的那样使用 mount(8) 和 df(1) 确认。
如需配给更多的磁盘设备则把它们加这个列表的后面。
在存储池上创建一个叫 home
的文件系统:
#
zfs create storage/home
像前文中提到的那样,在这个新建的文件系统上也可以启用压缩并保存多份拷贝, 可通过如下的命令实现:
#
zfs set copies=2 storage/home
#
zfs set compression=gzip storage/home
把用户的数据都拷贝过来并创建一个符号链接, 让他们开始使用这个新的目录:
#
cp -rp /home/* /storage/home
#
rm -rf /home /usr/home
#
ln -s /storage/home /home
#
ln -s /storage/home /usr/home
现在用户的数据应该都保存在新创建的
/storage/home
上了。试着添加一个新用户并以新的身份登录。
尝试创建一个可日后用来回退的快照:
#
zfs snapshot storage/home@08-30-08
请注意,快照选项将会抓取一个真实的文件系统,
而不是某个用户目录或文件。@
符号是用在文件系统名或卷名后面的分隔符。
当用户目录损坏时,可用如下命令恢复:
#
zfs rollback storage/home@08-30-08
如果想查看所有可用的快照,在文件系统的
.zfs/snapshot
目录下执行
ls
命令即可。
例如,执行如下命令来查看之前抓取的快照:
#
ls /storage/home/.zfs/snapshot
编写一个脚本定期抓取用户数据的快照是可行的, 但是久而久之,快照可能消耗掉大量的磁盘空间。 为了删除之前创建的快照,可使用以下命令:
#
zfs destroy storage/home@08-30-08
完成测试后,我们可以让
/store/home
成为真正的
/home
文件系统:
#
zfs set mountpoint=/home storage/home
使用 df
和
mount
命令确认我们的文件系统是否已经成了真正的
/home
:
#
mount
/dev/ad0s1a on / (ufs, local) devfs on /dev (devfs, local) /dev/ad0s1d on /usr (ufs, local, soft-updates) storage on /storage (zfs, local) storage/home on /home (zfs, local)#
df
Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235240 1628708 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032826 48737618 2% /usr storage 26320512 0 26320512 0% /storage storage/home 26320512 0 26320512 0% /home
这样 RAID-Z 的配置就完成了。为了借助每晚执行的 periodic(8) 获取文件系统的状态信息,我们进行如下配置:
#
echo 'daily_status_zfs_enable="YES"' >> /etc/periodic.conf
每种软 RAID
都有监测其 状态
的方法。
RAID-Z 的状态可以用下列命令查看:
#
zpool status -x
如果所有的存储池处于健康状态并且一切正常的话, 将返回如下信息:
all pools are healthy
如果存在问题,比如某个磁盘设备下线了, 那么存储池的状态将看上去大概是这个样子的:
pool: storage state: DEGRADED status: One or more devices has been taken offline by the administrator. Sufficient replicas exist for the pool to continue functioning in a degraded state. action: Online the device using 'zpool online' or replace the device with 'zpool replace'. scrub: none requested config: NAME STATE READ WRITE CKSUM storage DEGRADED 0 0 0 raidz1 DEGRADED 0 0 0 da0 ONLINE 0 0 0 da1 OFFLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors
上述信息表明, 管理员先前使用过如下命令让设备下线了:
#
zpool offline storage da1
有时候,我们会在切断系统电源之后替换下
da1
。
当系统再次上线时,使用下列命令替换磁盘:
#
zpool replace storage da1
至此可用不带 -x
选项的命令再次获取状态信息:
#
zpool status storage
pool: storage state: ONLINE scrub: resilver completed with 0 errors on Sat Aug 30 19:44:11 2008 config: NAME STATE READ WRITE CKSUM storage ONLINE 0 0 0 raidz1 ONLINE 0 0 0 da0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors
在这个例子中,一切都显示正常。
ZFS
使用 校验和
(checksum) 来验证存储数据的完整性。
当文件系统创建时,该特性就默认启用了,可使用以下的命令禁用:
#
zfs set checksum=off storage/home
我们强烈不建议这么做,
因为校验和只占用极少的存储空间,
并且在 “scrubbing” 的过程中,
校验和将被用来验证数据的完整性。
可以使用以下命令验证 storage
存储池里数据的完整性:
#
zpool scrub storage
该过程可能会很漫长,这取决于存储的数据量。 而且 I/O 操作非常密集, 所以在任何时间只能执行一个这样的操作。 scrub 完成之后,存储池的状态就更新了, 可使用如下的命令查看:
#
zpool status storage
pool: storage state: ONLINE scrub: scrub completed with 0 errors on Sat Aug 30 19:57:37 2008 config: NAME STATE READ WRITE CKSUM storage ONLINE 0 0 0 raidz1 ONLINE 0 0 0 da0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors
上述信息显示了 scrub 完成的时间, 并且确保在此时间后的很长的一段时间内,数据都将是完整的。
ZFS 支持不同的配额方式,包括:引用配额、总体配额、 用户配额、用户组配额。本节阐述了各种配额的方式与指令。
配额限制了某个数据集及其衍生数据集所能占据的总空间, 为衍生数据集的文件系统和快照所能占据的空间施加了限制。 当需要限制某个特定用户所能使用的空间时,配额非常有用。
配额不适用于卷,因为
volsize
属性本身就是一种隐式的配额。
refquota=size
能够为数据集所能消耗的总空间施加硬性限制。
然而,这一硬性限制并不包括衍生数据所占的空间,
例如文件系统和快照。
若要为 storage/home/bob
施加一个 10 GB 的总体配额,
可使用如下命令:
#
zfs set quota=10G storage/home/bob
用户配额限制了特定用户所能使用的空间。
一般格式为 userquota@user=size
,
其中用户名必须为下列格式中的一种:
POSIX
兼容的名字,例如
joe
。
POSIX
数值型 ID,例如
789
。
SID
名字,例如
joe.bloggs@example.com
。
SID
数值型 ID,例如
S-1-123-456-789
。
例如,使用如下命令给用户名为 joe
的用户施加 50 GB 的配额限制:
#
zfs set userquota@joe=50G
若要取消配额或者确保没有设置配额,使用如下命令:
#
zfs set userquota@joe=none
zfs get all
并不显示用户配额属性。
非 root
用户只能看到他们自己的配额,
除非他们被授予了 userquota
权限。
具有该权限的用户能够查看并设置所有用户的配额。
用户组配额限制了某个特定用户组所能消耗的空间。
一般格式为 groupquota@group=size
。
若要设置用户组 firstgroup
的配额为 50 GB,使用如下命令:
#
zfs set groupquota@firstgroup=50G
若要为用户组 firstgroup
取消配额,
或者确保没有为其设置配额,则使用如下命令:
#
zfs set groupquota@firstgroup=none
和用户配额属性一样,
非 root
用户只能查看他所在的用户组的配额。
而 root
或是取得了 groupquota
权限的用户则能够查看并设置所有用户组的配额。
若要显示在某个特定的文件系统或快照上,各个用户的配额及其消耗了多少空间,
可使用 zfs userspace
命令。
对于用户组的信息,则使用 zfs groupspace
命令。
关于上述命令的具体选项,可参考 zfs(1)。
具有足够权限的用户以及 root
可以使用如下命令列出 storage/home/bob
的配额:
#
zfs get quota storage/home/bob
ZFS 支持两种类型的空间预留。 本节阐述了这两种类型的实行方式和相关指令。
reservation
属性能够为数据集及其衍生数据集预留一块最小空间。
这就意味着,如果为 storage/home/bob
设置了 10 GB 的预留空间,当磁盘空间减少时,
至少要为该数据集预留 10 GB 可用空间。
refreservation
属性能够为数据集预留一块最小空间,
但并不包含其衍生数据,例如快照。
举例来说,如果要创建一份 storage/home/bob
的快照,
在 refreservation
之外必须有足够的空间,
操作才能成功。因为主数据集的衍生数据所需的空间并不计入
refreservation
,所以不会为其预留。
在许多场合下,任何形式的空间预留都非常有用。 例如,计划和测试新系统上的磁盘空间分配适用性; 或是确保在系统恢复的过程中,文件系统上有足够的可用空间。
reservation
属性的一般格式是
reservation=size
,
因此若要让 storage/home/bob
预留 10 GB 空间,使用如下命令:
#
zfs set reservation=10G storage/home/bob
若要确保没有设置预留空间,或者取消预留空间,使用如下命令:
#
zfs set reservation=none storage/home/bob
同理可设置 refreservation
属性,
其一般格式为 refreservation=size
。
若要检查在数据集 storage/home/bob
上是否设置了空间预留(reservations)或者引用空间预留(refreservations),
使用下列任一命令即可:
#
zfs get reservation storage/home/bob
#
zfs get refreservation storage/home/bob
本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读
文档,如不能解决再联系
<questions@FreeBSD.org>.
关于本文档的问题请发信联系
<doc@FreeBSD.org>.