ZFS - 数据完整性

By | 04月18日
Advertisement

对于很多的应用环境下,文件系统中数据完整性(Data Integrity)的重要性甚至高于文件系统的读写性能。因此,目前的文件系统或是存储系统都在数据完整性方面下了一番功夫。使用Checksum就是提高数据完整性的一种方式。

1. CheckSum数据校验

1.1 一般的Checksum校验方式

对于一般的文件系统来说,一个数据块的Checksum值是和对应的数据存放在一起的(如下图所示),在读取数据的同时就包含了对应数据的Checksum值,以此来检查数据是否有错误。

ZFS - 数据完整性

一般文件系统Checksum方式

这样的checksum方式可以检测到数据块中某个位发生错误。但是这样的校验方式存在很多问题,比如无法检测到静默数据错误(Silent Data Corruption)。这种错误的发生一般是来自硬件本省,比如磁盘损坏,硬件驱动错误,RAID卡损坏等等。举一个形象点得例子,假如我们在网上买了件瓷器,卖家将完整的瓷器包装好,交给快递公司,快递公司之后将瓷器原封不动地交给我们手中时,这里面的瓷器一定是完好无损的?显然是不一定的,说不定运输过程中给颠碎了。同样磁盘也有这样的问题,这些问题虽然难以被检测到,但是这些问题确实经常发生,严重影响了数据的完整性。在ZFS文件系统之前,还没有文件系统能够处理好这些问题。而ZFS在设计时就将这一切考虑到了,我们来看一下ZFS是ZFS通过Checksum来实现完整性校验的。

1.2 ZFS的Checksum校验方式

在ZFS文件系统中,数据的Checksum值并不是与数据存储在一起的,而是将数据的Checksum值存储在指向它的块指针中(如下图所示)。这样数据块的损坏并不会影响到Checksum,这样ZFS就维护了这样一棵树,每个节点都包含了它的子节点的Checksum值。(这里留下一个问题,这棵树的根是没有父节点的,它怎么校验?)。通过这棵树,ZFS可以完成自检工作,在自上而下的自检过程中,由于上面的Checksum值是经过验证的的,所以如果下面的数据发生错误,将很容易被检测出来。

ZFS - 数据完整性

ZFS Checksum存储方式

1.3 ZFS与ext4文件系统数据校验对比实例

下面,我们将通过一个实例来看看,如果我们偷偷修改了磁盘上的数据,ZFS和ext4文件系统将会有怎样的反应。

实验OS:Ubuntu 12.04(启动磁盘文件系统为ZFS)。

实验的主要流程:

1. 通过分别在ext4文件系统和ZFS文件系统中分别放置一个相同的文件allocator.txt。

2. 通过文件的在磁盘中的信息,找到第一个块位置(N),以这个blcok位界限,把整个磁盘分成三部分,N之前的部分,N,N之后的部分

3. 通过dd命令将三个部分分别独处放到三个不同的文件中

4. 修改分开后的N的文件,也就是文件的开头所在的block

5. 将三部分重新整合,重新挂载文件系统,看文件是否已经被修改过,文件系统能否发现文件已经被修改了。

首先,我们创建两个文件作为磁盘,分别在两个磁盘上创建ZFS文件系统和ext4文件系统。

# dd if=/dev/zero of=forzfsdiskfile bs=1024k count=100

# dd if=/dev/zero of=forextdiskfile bs=1024k count=100

# ls -lh

total 173M

-rw-r--r-- 1 root root 100M Apr 16 21:43 forextdiskfile

-rw-r--r-- 1 root root 100M Apr 16 21:42 forzfsdiskfile

# mkfs.ext4

mkfs.ext4 mkfs.ext4dev

# mkfs.ext4 -b 4096 forextdiskfile

(省略创建过程中的输出)

# mount -oloop forextdiskfile ext4mountpoint/

# zpool create poolfortest /root/forzfsdiskfile

# zfs create poolfortest/testpool

其次,我们分别放两个同样的文件到这两个新建的文件系统中。我们放入的文件是ZFS的首席设计师Jeff Bonwick之前提出的一篇大作:An Object-Caching Kernel Memory Allocator

# debugfs forextdiskfile

debugfs 1.42 (29-Nov-2011)

debugfs: stats

...

Directory Hash Seed: ea28afd5-8b52-4023-8957-f29217db095f

Journal backup: inode blocks

Directories: 2

Group 0: block bitmap at 8, inode bitmap at 24, inode table at 40

23760 free blocks, 25589 free inodes, 2 used directories, 25589 unused inodes

!!!放置文件之前,空闲的block数目位23760个 !!!

[Checksum 0x8aed]

# du -sh ext4mountpoint/allocator.txt

52Kext4mountpoint/allocator.txt

使用debugfs命令查看一下ext4文件系统中allocator.txt文件的相关信息

# debugfs forextdiskfile

debugfs 1.42 (29-Nov-2011)

debugfs: stats

...

Journal backup: inode blocks

Directories: 2

Group 0: block bitmap at 8, inode bitmap at 24, inode table at 40

23747 free blocks, 25588 free inodes, 2 used directories, 25587 unused inodes

!!!放置文件之后,空闲的block数目为23747个 !!!

[Checksum 0x3bdb]

debugfs: ls

2 (12) . 2 (12) .. 11 (20) lost+found 13 (4052) allocator.txt

debugfs: ncheck 13

InodePathname

13//allocator.txt

。。。

EXTENTS:

(0-12):24592-24604

我们来看一下,allocator.txt文件的前几行信息:

---------------------------------------------------------------------------------------------------------------------

The Slab Allocator:

An Object-Caching Kernel Memory Allocator

Jeff Bonwick

Sun Microsystems

Abstract

This paper presents a comprehensive design overview of the SunOS 5.4 kernel

---------------------------------------------------------------------------------------------------------------------

由于我们在创建ext4文件系统时候就已经确定了,该文件系统的Block大小为4096 Bytes。同时我们注意到,在放置文件之前,文件系统的空闲block数目是:23760,放置之后空闲block数目是23747。也就是说,allocator.txt文件一共占用了13个block。同时它对应的inode为13。通过debugfs我们也可以看到,它的13个block位置:(0-12):24592-24604。

下面,将把forextdisk分成三个部分,修改文件,然后重组,确认:

# dd if=forextdiskfile of=/tmp/forextdisk_part1 count=24592 bs=4096

# dd if=forextdiskfile of=/tmp/extfirstblock bs=4096 skip=24592 count=1

# dd if=forextdiskfile of=/tmp/forextdisk_part2 skip=24593 bs=4096

# vi /tmp/extfirstblock

# dd if=/tmp/extfirstblock of=/tmp/extfirstblock2 ibs=4096 obs=4095 count=1

# 以下开始合并磁盘文件

# cat /tmp/extfirstblock2 >> /tmp/forextdisk_part1

# cat /tmp/forextdisk_part2 >> /tmp/forextdisk_part1

# cp -pRf /tmp/forextdisk_part1 forextdiskfile、

# 一下开始重新挂载文件系统

# fsck.ext4

fsck.ext4 fsck.ext4dev

# fsck.ext4

fsck.ext4 fsck.ext4dev

# fsck.ext4 -v forextdiskfile

e2fsck 1.42 (29-Nov-2011)

forextdiskfile: clean, 12/25600 files, 1853/25600 blocks

# mount -o loop forextdiskfile ext4mountpoint/

# 这里你可以通过debugfs命令查看forextdiskfile磁盘文件中allocator.txt文件的信息,其结果与之前看到的相同。这是我们再来看allocator.txt的前几行

# head ext4mountpoint/allocator.txt

The Slab Allocator:

An Object-Cachedd Kernel Memory Allocator

这里已经不是“Caching“了,但是文件系统什么也没发现。

Jeff Bonwick

Sun Microsystems

Abstract

This paper presents a comprehensive design overview of the SunOS 5.4 kernel

ext4对于我们偷偷修改数据的行为一点也不知情,接下来,我们看看ZFS有什么表现:

# ls -i /poolfortest/testpool/

7 allocator.txt

# zdb -dddddd poolfortest/testpool 7

Dataset poolfortest/testpool [ZPL], ID 40, cr_txg 697, 81.5K, 7 objects, rootbp DVA[0]= DVA[1]= 。。。

Indirect blocks:

0 L0 0:32e00:ce00 ce00L/ce00P F=1 B=702/702

segment [0000000000000000, 000000000000ce00) size 51.5K

# 从这里我们可以看出,整个文件放在一个连续的空间内,位于pool中的0号磁盘,0x32e00偏移处,大小为0xce00;其次,从DVA中的可以判断Block大小为0x200,即512字节。

# 那么我们可以计算allocator文件的第一个Block的位置。(0x400000 + 0x32e00)/ 512 = 8599

# dd if=forzfsdiskfile of=/tmp/zfsdiskfile_part1 bs=512 count=8599

# dd if=forzfsdiskfile of=/tmp/zfsheadfile bs=512 skip=8599 count=10

# dd if=forzfsdiskfile of=/tmp/zfsdiskfile_part2 bs=512 skip=8609

# vi /tmp/zfsheadfile

# 以下开始,我们将修改过的三部分文件重新整合到一起

# cp -pRf /tmp/zfsdiskfile_part1 /root/forzfsdiskfile

# dd if=/tmp/zfsheadfile of=/tmp/zfsheadfile_changed bs=5120 count=1

# cat /tmp/zfsheadfile_changed >> /root/forzfsdiskfile

# cat /tmp/zfsdiskfile_part2 >> /root/forzfsdiskfile

# zpool import -d /root/ poolfortest

# zpool status poolfortest

pool: poolfortest

state: ONLINE

scan: none requested

config:

NAME STATE READ WRITE CKSUM

poolfortest ONLINE 0 0 0

/root/forzfsdiskfile ONLINE 0 0 0

errors: No known data errors

# 我们来看看文件

# ls /poolfortest/testpool

allocator.txt

# head /poolfortest/testpool/allocator.txt

head: error reading `/poolfortest/testpool/allocator.txt': Input/output error

# zpool status -v

pool: poolfortest

state: ONLINE

status: One or more devices has experienced an error resulting in data

corruption. Applications may be affected.

action: Restore the file in question if possible. Otherwise restore the

entire pool from backup.

see: http://zfsonlinux.org/msg/ZFS-8000-8A

scan: none requested

config:

NAME STATE READ WRITE CKSUM

poolfortest ONLINE 0 0 2

/root/forzfsdiskfile ONLINE 0 0 4

errors: Permanent errors have been detected in the following files:

/poolfortest/testpool/allocator.txt

操作过程中,我们有一个计算Block的公式:(0x400000 + 0x32e00)/ 512 = 8599,这里的0x400000,表示了,磁盘的最前面4M空间(保留空间+Vdev Label),如果有疑问的话,可以看一下我前面两篇博客: ZFS - Ondiskformat 第一章 虚拟设备(vdevs),Vdev Label以及Boot BlockZFS的校验算法,这里面说明了前面4M的详细分配情况, ZFS - Ondiskformat 第二章 块指针、间接块,这里面有说明如何计算偏移地址(2.1节)。

OK,到这里,我们通过ext4与ZFS两种文件系统在应对静默数据损坏时的效果,可以看出ZFS的完美地发现了我们修改数据的事情。需要说明的是,我们实验的时候使用的是条带化的磁盘,如果我们创建pool的时候使用mirror的话,ZFS将会自动从有正确数据的磁盘上帮我们修复错误数据,这个过程无需我们手动干预。

其实ZFS在保证数据完整性方面不仅仅体现在这一个方面。下面我们在给出一些介绍:

2. 其它实现数据完整性方式

2.1 元数据的保护

元数据在文件系统中是十分重要的,一个元数据块的损坏可能导致多块数据无法访问。因此,ZFS采用多份元数据的方式来保护它们。在 ZFS - Ondiskformat 第二章 块指针、间接块这篇博客中我们可以知道,ZFS的块指针中有三个DVA(数据虚拟地址),对于普通的数据块,ZFS只使用一个DVA,也就是说数据只存储一份,对于普通的元数据,ZFS使用两个DVA,这样的元数据将会在磁盘中有相同的两个备份,对于更重要的元数据,比如文件系统的根,则使用三个DVA,这样的数据将被存储三份。

2.2 Mirror与RAID

ZFS是一个整合了文件系统与卷管理系统的新型文件系统,所以ZFS也提供了Mirror和RAID功能。这里需要的是,如果同时使用了硬件的RAID,则可能会与ZFS的RAID相冲突,这将导致ZFS将只会检测数据的完整性,而并不会自动修复错误的数据。

如果我们只有一块磁盘,而且我们创建pool时也没有做RAID或是mirror,我们也可以让ZFS为我们的每个数据存储多份来保护我们的数据。这个只要设置文件系统的copies属性就好了,但是如果设置了copies属性为2,那么磁盘空间也会相应地减半(因为我们每个数据都存储了两次),依次类推。

3. ZIO流水线中的Checksum的实现

点击(此处)折叠或打开

  1. zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
  2. {{NULL, NULL}, 0, 0, 0, "inherit"},
  3. {{NULL, NULL}, 0, 0, 0, "on"},
  4. {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "off"},
  5. {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "label"},
  6. {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "gang_header"},
  7. {{fletcher_2_native, fletcher_2_byteswap}, 0, 1, 0, "zilog"},
  8. {{fletcher_2_native, fletcher_2_byteswap}, 0, 0, 0, "fletcher2"},
  9. {{fletcher_4_native, fletcher_4_byteswap}, 1, 0, 0, "fletcher4"},
  10. {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 0, 1, "sha256"},
  11. {{fletcher_4_native, fletcher_4_byteswap}, 0, 1, 0, "zilog2"},
  12. {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "noparity"},
  13. };
  14. typedef struct zio_checksum_info {
  15. zio_checksum_t *ci_func[2]; /* checksum function for each byteorder */
  16. int ci_correctable; /* number of correctable bits */
  17. int ci_eck; /* uses zio embedded checksum? */
  18. int ci_dedup; /* strong enough for dedup? */
  19. char *ci_name; /* descriptive name */
  20. } zio_checksum_info_t

通过这两个变量的定义,在ZIO流水线中,我们使用一个整数来代表Checksum算法,通过这个整数在上面的zio_checksum_table中查找,直接就可以调用该checksum的计算算法,对数据计算对应的checksum值。

对于ZFS的Checksum设计,源码中还给出了以下的几个原因:

1) 不同类型的数据需要不同强度的Checksum值,比如SPA的元数据就需要高强度的Checksum算法,而对于用户数据,则可以由用户来在速度和强度之间进行权衡选择。

2) 加密用的算法是在不断的发展的,说不定未来的某一天会出现一种更强但是计算速度同样更快的算法,通过这种方式就很容易将该算法加入到代码中。

3) 如果有人设计了速度更快的硬件,我们也可以迅速利用那样的硬件。

4. 总结

ZFS是一种新型的文件系统,它在保证数据完整性方面做足了功夫以保护用户的数据。很多的设计都具有颠覆性的意义,比如将RAID,Mirror整合到文件系统中等等。这一切让我们更加放心地使用ZFS。

Similar Posts:

  • ZFS-Sun 的最新文件系统

    目录: * ZFS 概览 * ZFS 数据完整性和安全性 o 基于事务的写复制操作 o 端对端校验和 * ZFS 可伸缩性 o 128 位体系结构 o 动态元数据 o 文件系统性能 * 资源 ZFS 概览 Sun 最近为 Solaris 10 06/06 操作系统添加了 ZFS,它是对传统 UNIX 文件系统的一次彻底的创新性重新设计.Sun 工程师和开放源代码组织成员汲取市场上一些普遍的最佳做法(如 Network Appliances 快照.VERITAS 基于对象的存储管理.事务及校验和)

  • 【译】ZFS最佳实践指南-Part7

    4 ZFS管理/观察工具 5 虚拟化事项 5.1 ZFS与虚拟带库(VTL) 虚拟带库解决方案是通过对模拟磁带.磁带驱动器和带库的使用而出现的一种硬件与软件的结合体.虚拟带库被用于备份/存档系统,被定位于用来减少硬件和软件的成本. 虚拟带库是大量磁盘空间的吞噬者,我们相信ZFS将允许其更有效和安全的管理大量的.在线磁盘空间. * Falconstor虚拟带库–该虚拟带库需要磁盘块设备来工作.其不使用外部文件系统.因此目前不能使用ZFS和Falconstor虚拟带库相结合的方法. * Copan

  • ZFS文件系统十大功能特点

    Sun在2005年推出了开源文件系统ZFS,最初Sun是为OpenSolaris设计的,随着时间的发展,用户逐渐发现其一些良好的功能,下面列举的ZFS十大功能,是ZFS支持者通过这些年应用体会出来的. 以下是ZFS支持者认为ZFS具备的十大最佳功能特性: 1.元数据校验和确保数据完整性 数据完整性在ZFS中具有非常高的重要性,也是很多ZFS功能的前决条件. ZFS文件系统采用了256位校验和,当向磁盘写入数据的时候,校验和就会被作为元数据与它相关的数据分开保存.与普通的磁盘块校验和不同的 是,这

  • FreeBSD7 boot ZFS存储的规划

    FreeBSD 7.0具备以 ZFS 作为根文件系统的能力.本文将以一台有6块硬盘的服务器介绍从FreeBSD/amd64 7.0 LiveFS光盘(随发行版发行的LiveCD系统)全新安装一份FreeBSD,并使用ZFS作为根目录的具体方法. 存储的规划 我们假定有6块750GB的SATA硬盘,ad0-ad5:系统有8GB RAM,希望作为存储服务器.在尽量保证数据完整性和性能的前提下,我们会希望有: 使用五块硬盘作为RAIDZ1或RAIDZ2卷:一块硬盘作为备盘: 系统的引导和配置信息保存2

  • ZFS文件系统安装freebsd

    FreeBSD 7.0具备以 ZFS 作为根文件系统的能力.本文将以一台有6块硬盘的服务器介绍从FreeBSD/amd64 7.0 LiveFS光盘(随发行版发行的LiveCD系统)全新安装一份FreeBSD,并使用ZFS作为根目录的具体方法. 存储的规划 我们假定有6块750GB的SATA硬盘,ad0-ad5:系统有8GB RAM,希望作为存储服务器.在尽量保证数据完整性和性能的前提下,我们会希望有: 使用五块硬盘作为RAIDZ1或RAIDZ2卷:一块硬盘作为备盘: 系统的引导和配置信息保存2

  • 汉澳sinox的先进文件系统zfs轻松击败微软ReFS和linux的btrfs

    汉澳 sinox2014引入的zfs先进文件系统轻松击败微软的ReFS 说明汉澳sinox借助开源的力量已经在文件系统获得领先优势,适合打造高性能存储服务器. 这个事实告诉人们,windows并非不可战胜. 文件系统比拼:微软ReFS VS ZFS 作者:雷霆出处:IT专家网2013-07-30 08:47 [IT专家网存储]存储的优点,一般认为是硬件驱动.基于RAID的文件系统的高可靠.真相是,显著的潜在错误依然存在,特别是随着系统为云架构和大数据应用程序扩展.这种潜在的错误,由于操作系统或者

  • ZFS大大提高文件系统的稳定性

    现在对于存储的大量需求,存储设备急速成长.CTO半夜会惊醒的问题又增加了几项.如何降低存储管理的成本?如何提高文件系统的可靠性?实为当务之急.Sun公司最近提出的ZFS, 是否是一条可行之途,令许多人都很感兴趣. 记得当你给你的电脑加内存时,系统重新起动之后,你不必作任何额外的动作,电脑自己就能认得这些新加的内存,而加以使用.当你加了一个硬盘到你的电脑时,到你能够使用到这个新加的硬盘时,其中要采取的步骤,就没有那么简单了.但是ZFS可以把使用新加硬盘的步骤,简化到几乎和使用新加内存一样的简单.对

  • 使用zfs进行pg的pitr恢复测试

    前段时间做了一下zfs做pg的增量恢复测试,mark一下. 服务器信息: 主机:192.168.173.43 备机:192.168.173.41 主备使用流复制搭建,在备机上面进行了zfs快照备份. 做zfs快照备份: 备机: 1.在2016-04-02 15:43:34对存放pg数据的zfs dataset zp1/data01进行快照备份. 数据总大小135MB,使用zfs快照备份后的大小为90.5KB 测试主机误删数据: 主机: 1.主机在build_test表中2016-04-02 15

  • ZFS数据缓存(Part I)

    Copyright © 2009, The e. Publishing Dept. of Morpho Studio (Spruce Int. Found.® ) All rights reserved. 从硬件模拟的层面来看,ZFS可以看做是一个功能丰富.管理操作方便的磁盘阵列卡. 磁盘阵列卡是连接高速的系统"总线"和低速的"磁盘"设备的桥梁,为了平衡"总线"和"磁盘"之间的速度差异,改善磁盘存储系统的性能,效果最显著的解决

  • 用FreeBSD10搭建基于ZFS的iSCSI服务

    概述 对于ZFS我是一直在强烈推荐的,因为实在太好用了.但是直到现在,它还是只能运行于Oracle的Solaris和FreeBSD两个系统上,为了将它分享给别的系统只能通过NAS或SAN的方式. NAS的方式很简单,我一直在用Samba实现,当然NFS也是可以的,SAN的话之前还没试过.使用上当然是SAN更好一些,而且现在网速也够快.虽然对于存储来说,NAS和SAN都是外部存储,但对于客户机来说,它知道NAS是网络设备,而SAN则会被视同本地设备,这是二者的主要区别.之所以会这样,是因为NAS走

Tags: