ZFS/Virtual disks
该篇文章涵盖了关于 ZFS 的一些基本任务和用例。它与 ZFS 主文章有所不同,此处的案例使用了基于虚拟磁盘搭建的 zpool。因此,只要用户不在创建出的磁盘中存放任何关键数据,他们就无需担心任何的数据丢失问题。
在该文章的案例中使用了多个虚拟磁盘作为 ZFS 的 VDEV。用户可以用现有物理磁盘创建 VDEV,也可以在空闲内存足够时使用 tempfs(内存盘)创建 VDEV。
由于许可证的差异问题,ZFS 二进制文件和内核模块可以很容易地以源代码进行分发,但不容易以软件包和预编译集形式进行分发。详细信息可参考 ZFS#安装。
创建和删除 Zpools[编辑 | 编辑源代码]
管理 ZFS 非常简单,只需要用到两个工具:
/usr/bin/zpool
/usr/bin/zfs
镜像[编辑 | 编辑源代码]
对于仅包含两个磁盘的带冗余 zpool,建议使用类似 RAID1 对数据镜像镜像的镜像模式。镜像同时可以作为 Raidz 配置的替代,以获得出人意料的结果。关于 vdev 镜像的详细信息可参考这里。
RAIDZ1[编辑 | 编辑源代码]
RAIDZ1 的最低硬盘数需求为 3。为了优化存储空间效率和达到性能最佳点,建议盘数遵顼“二次方加验证盘”的规则。对于 RAIDZ-1,建议使用 3(2+1),5(4+1),或者 9(8+1)块盘。下列示例将使用最简单的(2+1)。
创建 3 个 2G 的文件作为虚拟硬盘:
$ for i in {1..3}; do truncate -s 2G /scratch/$i.img; done
创建 RAIDZ1:
# zpool create zpool raidz1 /scratch/1.img /scratch/2.img /scratch/3.img
注意已成功创建并挂载了一个 3.91G 的 zpool:
# zfs list
NAME USED AVAIL REFER MOUNTPOINT test 139K 3.91G 38.6K /zpool
可通过如下方式获取设备信息:
# zpool status zpool
pool: zpool state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM zpool ONLINE 0 0 0 raidz1-0 ONLINE 0 0 0 /scratch/1.img ONLINE 0 0 0 /scratch/2.img ONLINE 0 0 0 /scratch/3.img ONLINE 0 0 0 errors: No known data errors
要删除 zpool:
# zpool destroy zpool
RAIDZ2 和 RAIDZ3[编辑 | 编辑源代码]
高阶 ZRAID 的操作与上述步骤类似,只需调整 for 循环参数来调整创建的文件数、在创建 zpool 时指定“raidz2”或“raidz3”,并补充上额外添加的镜像文件。
总结下 Toponce 的指南:
- RAIDZ2 硬盘数应为 4(2+2),6(4+2),10(8+2)或 18(16+2)。
- RAIDZ3 硬盘数应为 5(2+3),7(4+3),11(8+3)或 19(16+3)。
线性扩展[编辑 | 编辑源代码]
This setup is for a JBOD, good for 3 or less drives normally, where space is still a concern and you are not ready to move to full features of ZFS yet because of it. RaidZ will be your better bet once you achieve enough space to satisfy, since this setup is NOT taking advantage of the full features of ZFS, but has its roots safely set in a beginning array that will suffice for years until you build up your hard drive collection.
Assemble the Linear Span:
# zpool create zpool san /dev/sdd /dev/sde /dev/sdf
# zpool status zpool
pool: zpool state: ONLINE scan: scrub repaired 0 in 4h22m with 0 errors on Fri Aug 28 23:52:55 2015 config: NAME STATE READ WRITE CKSUM zpool ONLINE 0 0 0 sde ONLINE 0 0 0 sdd ONLINE 0 0 0 sdf ONLINE 0 0 0 errors: No known data errors
创建与删除数据集[编辑 | 编辑源代码]
以下演示了如何创建带压缩的子数据集:
- 创建数据集
# zfs create -p -o compression=on san/vault/falcon/snapshots # zfs create -o compression=on san/vault/falcon/version # zfs create -p -o compression=on san/vault/redtail/c/Users
- 接下来列出数据集 (this was a linear span)
$ zfs list
Note, there is a huge advantage(file deletion) for making a 3 level dataset. 如果你存放了大量的数据,通过使用数据集进行切分,可使得删除文件时只需删除对应的数据集,而无需等待删除递归操作完成。
显示并设置属性[编辑 | 编辑源代码]
Without specifying them in the creation step, users can set properties of their zpools at any time after its creation using /usr/bin/zfs
.
显示属性[编辑 | 编辑源代码]
To see the current properties of a given zpool:
# zfs get all zpool
修改属性[编辑 | 编辑源代码]
Disable the recording of access time in the zpool:
# zfs set atime=off zpool
Verify that the property has been set on the zpool:
# zfs get atime
NAME PROPERTY VALUE SOURCE zpool atime off local
Add content to the Zpool and query compression performance[编辑 | 编辑源代码]
Fill the zpool with files. For this example, first enable compression. ZFS uses many compression types, including, lzjb, gzip, gzip-N, zle, and lz4. Using a setting of simply 'on' will call the default algorithm (lzjb) but lz4 is a nice alternative. See zfsprops(7) § compression for more.
# zfs set compression=lz4 zpool
In this example, the linux source tarball is copied over and since lz4 compression has been enabled on the zpool, the corresponding compression ratio can be queried as well.
$ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.11.tar.xz $ tar xJf linux-3.11.tar.xz -C /zpool
To see the compression ratio achieved:
# zfs get compressratio
NAME PROPERTY VALUE SOURCE zpool compressratio 2.32x -
Simulate a disk failure and rebuild the Zpool[编辑 | 编辑源代码]
To simulate catastrophic disk failure (i.e. one of the HDDs in the zpool stops functioning), zero out one of the VDEVs.
$ dd if=/dev/zero of=/scratch/2.img bs=4M count=1 2>/dev/null
Since we used a blocksize (bs) of 4M, the once 2G image file is now a mere 4M:
$ ls -lh /scratch
total 317M -rw-r--r-- 1 facade users 2.0G Oct 20 09:13 1.img -rw-r--r-- 1 facade users 4.0M Oct 20 09:09 2.img -rw-r--r-- 1 facade users 2.0G Oct 20 09:13 3.img
The zpool remains online despite the corruption. Note that if a physical disc does fail, dmesg and related logs would be full of errors. To detect when damage occurs, users must execute a scrub operation.
# zpool scrub zpool
Depending on the size and speed of the underlying media as well as the amount of data in the zpool, the scrub may take hours to complete. The status of the scrub can be queried:
# zpool status zpool
pool: zpool state: DEGRADED status: One or more devices could not be used because the label is missing or invalid. Sufficient replicas exist for the pool to continue functioning in a degraded state. action: Replace the device using 'zpool replace'. see: http://zfsonlinux.org/msg/ZFS-8000-4J scan: scrub repaired 0 in 0h0m with 0 errors on Sun Oct 20 09:13:39 2013 config: NAME STATE READ WRITE CKSUM zpool DEGRADED 0 0 0 raidz1-0 DEGRADED 0 0 0 /scratch/1.img ONLINE 0 0 0 /scratch/2.img UNAVAIL 0 0 0 corrupted data /scratch/3.img ONLINE 0 0 0 errors: No known data errors
Since we zeroed out one of our VDEVs, let us simulate adding a new 2G HDD by creating a new image file and adding it to the zpool:
$ truncate -s 2G /scratch/new.img # zpool replace zpool /scratch/2.img /scratch/new.img
Upon replacing the VDEV with a new one, zpool rebuilds the data from the data and parity info in the remaining two good VDEVs. Check the status of this process:
# zpool status zpool
pool: zpool state: ONLINE scan: resilvered 117M in 0h0m with 0 errors on Sun Oct 20 09:21:22 2013 config: NAME STATE READ WRITE CKSUM zpool ONLINE 0 0 0 raidz1-0 ONLINE 0 0 0 /scratch/1.img ONLINE 0 0 0 /scratch/new.img ONLINE 0 0 0 /scratch/3.img ONLINE 0 0 0 errors: No known data errors
快照和恢复已删除的文件[编辑 | 编辑源代码]
ZFS 是写时复制文件系统,所有文件在写入那一刻时就已存入。保存文件修改实际上创建了同一文件的拷贝及其修改记录。快照实际上利用了这一特性,使得用户可以访问快照创建时的旧版本文件。
/usr/bin/zfs list
会给出准确的 zpool 可用及剩余空间数据。为了简化示例,我们将在 zpool 中创建数据集并创建快照,快照可以对整个 zpool 或者池中的单个数据集进行创建,区别只有命名方式:
快照目标 | 快照名 |
---|---|
整个 zpool | zpool@snapshot-name |
数据集 | zpool/dataset@snapshot-name |
创建新数据集并获取所有权:
# zfs create zpool/docs # chown facade:users /zpool/docs
Time 0[编辑 | 编辑源代码]
添加一些文件到新数据集中(/zpool/docs):
$ wget -O /zpool/docs/Moby_Dick.txt https://www.gutenberg.org/ebooks/2701.txt.utf-8 $ wget -O /zpool/docs/War_and_Peace.txt https://www.gutenberg.org/ebooks/2600.txt.utf-8 $ wget -O /zpool/docs/Beowulf.txt https://www.gutenberg.org/ebooks/16328.txt.utf-8
# zfs list
NAME USED AVAIL REFER MOUNTPOINT zpool 5.06M 3.91G 40.0K /zpool zpool/docs 4.92M 3.91G 4.92M /zpool/docs
这意味着下载的书籍占用了 /zpool/docs 中 4.92M 的空间。
Time +1[编辑 | 编辑源代码]
接下来为数据集创建快照:
# zfs snapshot zpool/docs@001
再运行一次 list 命令:
# zfs list
NAME USED AVAIL REFER MOUNTPOINT zpool 5.07M 3.91G 40.0K /zpool zpool/docs 4.92M 3.91G 4.92M /zpool/docs
注意,因为这三个文件没有被修改,因此 USED 一列没有变更,意味着快照不占用 zpool 空间。
我们可以通过如下方式列出快照,并确认快照不占用存储空间,而是引用了原始文件,这些文件共占用 4.92M:
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT zpool/docs@001 0 - 4.92M -
Time +2[编辑 | 编辑源代码]
接下来添加些新文件,并创建新快照:
$ wget -O /zpool/docs/Les_Mis.txt https://www.gutenberg.org/ebooks/135.txt.utf-8 # zfs snapshot zpool/docs@002
再次使用 list 来查看空间变化:
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT zpool/docs@001 25.3K - 4.92M - zpool/docs@002 0 - 8.17M -
可以看到 001 快照的元数据占用了 25.3K 大小,并依旧引用了之前的 4.92M 数据;新快照不占用任何空间,并引用了总共 8.17M 的数据。
Time +3[编辑 | 编辑源代码]
接下来我们模拟下意外覆盖文件导致的数据丢失:
$ echo "this book sucks" > /zpool/docs/War_and_Peace.txt
与之前一样,再创建一个快照:
# zfs snapshot zpool/docs@003
接下来列出快照,可见被引用的数据减少了 3.1M:
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT zpool/docs@001 25.3K - 4.92M - zpool/docs@002 25.5K - 8.17M - zpool/docs@003 0 - 5.04M -
我们可以在一个或者多个旧快照中找到该文件的未损坏版本。ZFS 将快照存放在 zpool 中一个隐藏文件夹内:/zpool/files/.zfs/snapshot
:
$ ls -l /zpool/docs/.zfs/snapshot
total 0 dr-xr-xr-x 1 root root 0 Oct 20 16:09 001 dr-xr-xr-x 1 root root 0 Oct 20 16:09 002 dr-xr-xr-x 1 root root 0 Oct 20 16:09 003
我们可以从任意一个快照中复制一份未损坏版本的书到 zpool 内或外部的任意地址:
% cp /zpool/docs/.zfs/snapshot/002/War_and_Peace.txt /zpool/docs
# zfs set snapdir=visible zpool/docs
接下来进入一个或各个快照文件夹:
$ cd /zpool/docs/.zfs/snapshot/001 $ cd /zpool/docs/.zfs/snapshot/002
重复 df 命令:
$ df -h | grep zpool zpool 4.0G 0 4.0G 0% /zpool zpool/docs 4.0G 5.0M 4.0G 1% /zpool/docs zpool/docs@001 4.0G 4.9M 4.0G 1% /zpool/docs/.zfs/snapshot/001 zpool/docs@002 4.0G 8.2M 4.0G 1% /zpool/docs/.zfs/snapshot/002
例如:
# zpool export zpool # zpool import -d /scratch/ zpool $ df -h | grep zpool zpool 4.0G 0 4.0G 0% /zpool zpool/docs 4.0G 5.0M 4.0G 1% /zpool/docs
Time +4[编辑 | 编辑源代码]
现在一切已恢复正常,我们可以为目前状态再次创建一个快照:
# zfs snapshot zpool/docs@004
此时的 list 输出为:
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT zpool/docs@001 25.3K - 4.92M - zpool/docs@002 25.5K - 8.17M - zpool/docs@003 155K - 5.04M - zpool/docs@004 0 - 8.17M -
列出快照[编辑 | 编辑源代码]
需要指出,这一简单但十分重要的命令在同类文章中经常被忽略,因此有必要特别提一下。
使用如下命令列出系统中的所有快照:
$ zfs list -t snapshot
删除快照[编辑 | 编辑源代码]
可存放的快照数量最大为 2^64,用户可以通过如下命令删除快照:
# zfs destroy zpool/docs@001
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT zpool/docs@002 3.28M - 8.17M - zpool/docs@003 155K - 5.04M - zpool/docs@004 0 - 8.17M -
Troubleshooting[编辑 | 编辑源代码]
If your system is not configured to load the zfs pool upon boot, or for whatever reason you want to manually remove and add back the pool, or if you have lost your pool completely, a convenient way is to use import/export.
If your pool was named <zpool>
# zpool import -d /scratch zpool
If you have any problems accessing your pool at any time, try export and reimport.
# zpool export zpool # zpool import -d /scratch zpool