ZFS/Virtual disks

来自 Arch Linux 中文维基
< ZFS

该篇文章涵盖了关于 ZFS 的一些基本任务和用例。它与 ZFS 主文章有所不同,此处的案例使用了基于虚拟磁盘搭建的 zpool。因此,只要用户不在创建出的磁盘中存放任何关键数据,他们就无需担心任何的数据丢失问题。

在该文章的案例中使用了多个虚拟磁盘作为 ZFS 的 VDEV。用户可以用现有物理磁盘创建 VDEV,也可以在空闲内存足够时使用 tempfs(内存盘)创建 VDEV。

注意: 使用文件作为 VDEV 是测试 ZFS 的好方法,但不建议用于存放实际数据。

由于许可证的差异问题,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
提示:This option like many others can be toggled off when creating the zpool as well by appending the following to the creation step: -O atime-off

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 是写时复制文件系统,所有文件在写入那一刻时就已存入。保存文件修改实际上创建了同一文件的拷贝及其修改记录。快照实际上利用了这一特性,使得用户可以访问快照创建时的旧版本文件。

注意: 因 ZFS 使用快照方式较为特殊,当使用快照时,像 df 一类汇报文件系统空间的 Linux 应用会给出不准确的数据。/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
注意: <TAB> 自动补全在默认情况下不可用,但可通过修改存储池或数据集的 snapdir 属性来启用。
# 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 设为离线并重新挂载,或是重启服务器,可以撤销 .zfs 下所有文件夹可见。

例如:

# 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