logo资料库

ZFS文件系统.pdf

第1页 / 共17页
第2页 / 共17页
第3页 / 共17页
第4页 / 共17页
第5页 / 共17页
第6页 / 共17页
第7页 / 共17页
第8页 / 共17页
资料共17页,剩余部分请下载后查看
ZFS 文件系统 1. ZFS 介绍 1.1 ZFS 发展史 ZFS 是由 SUN 公司的 Jeff Bonwick 和 Matthew Ahrens 大神于 2001 年领导 设计开发,并在 2004 年 2 月 14 日发布的集合了文件系统处理逻辑和卷管理器 功能的文件系统。ZFS 的全拼是 Zettabyte File System,Zetta 是一个数量单位, 1ZB = 1024EB = 1048576 PB,而 facebook 目前最大的单个 HDFS 集群中存储了 100PB 的 log 数据。当然单台服务器不可能也不会存储这么多数据,这从一个 侧面说明了 zfs 的存储容量从实际使用中来说是没有上限的。zfs 不是类似于 hdfs 的分布式文件系统或者 lustre 之类的集群文件系统,通常可以用来作 HDFS 和 lustre 的后端存储文件系统使用。 SUN 公司从 2008 年开始组织并支持开源 open solaris 项目,ZFS 是其中一 个重要的组成部分,随着 oracle 公司收购了 sun,并于 2010 年停止了 open solaris 的开发工作,原先的 ZFS 核心开发者们也逐步的离开了 oracle,他们中 的一部份人继续着 ZFS 的开发,参与或者组成了 Joyent、Nexenta、Delphix 等 以 opensolaris 或 ZFS 为蓝本的公司,他们的 oracle 个人 blog 也随着离开 oracle 停止更新或者无法访问,而 open solaris 的社区也将在 2013 年 3 月 24 日关闭, 届时我们将失去学习一个学习目前最为先进的商业操作系统的途径,,作为软 件设计中的一项杰作,ZFS 值得我们深入的学习,包括它斟酌权衡的设计,令 人赞叹的细节实现和追求完美的态度,在接下来的文章中将为各位读者一一说 明和展现。
1.2 ZFS 特性 将 ZFS 称为文件系统有点名不副实,因为它在传统意义上不仅仅是个文件系 统。ZFS 将逻辑卷管理器的概念与功能丰富的和可大规模扩展的文件系统结合 起来。让我们开始先探索一些 ZFS 所基于的原则。 - 首先,ZFS 使用池存储模型,而不是传统的基于卷的模型。这意味着 ZFS 视存储为可根据需要动态分配(和缩减)的共享池。这优于传统模型,在传 统模型中,文件系统位于卷上,使用独立卷管理器来管理这些资产。 - ZFS 内嵌入的是重要功能集(如快照、即写即拷克隆、连续完整性检查和 通过 RAID-Z 的数据保护)的实现。 - 更进一步,可以在 ZFS 卷的顶端使用您自己最喜爱的文件系统(如 ext4) 这意味着您可以获得那些 ZFS 的功能,如独立文件系统中的快照(该文件系统 可能并不直接支持它们)。 但是 ZFS 不只是组成有用文件系统的功能集合。相反,它是构建出色文件系 统的集成和补充功能的集合。让我们来看看其中的一些功能,然后再看看它们 的一些实际应用。ZFS 作为一个划时代的文件系统,被移植到了多个 OS 平台 上,它具有的特性主要如下: 1. 接近于无限的存储空间 ZFS 合并了卷管理功能来提取底层物理存储设备到文件系统。ZFS 对存储池(称 为 zpools)进行操作,而不是直接查看物理块设备,存储池构建自虚拟驱动器, 可由驱动器或驱动器的一部分物理地进行表示。 ZFS 针对若干磁盘组成的集合抽象出了 zpool 的概念,而文件系统则是活动 的,每个文件系统实例可以从 zpool 中分配空间,zpool 的大小可以动态变化, 在空间不足的时候可以动态添加磁盘,在空间充足的时候也可以通过移动数据 的办法抽调出磁盘。ZFS 的一些理论极限如下:对于任意 ZFS 文件系统实例, 支持 248 个快照,支持 248 个文件,单个文件系统实例最大 16EB,单个文件最 大 16EB,单个 zpool 最大 128ZB,每个 zpool 最多支持 264 个设备等等。 2. COW 事务模型
COW 是 Copy On Write 的缩写,是指在对数据进行修改时并不是直接原地修 改,而是拷贝一份新的与修改的内容合并。使用COW 的一个例子就是Unix 的 fork 函数实现,通常fork 的过程中子进程需要拷贝父进程的页表等虚拟内存信 息,而如果子进程对拷贝的页表修改较少这样的拷贝工作就会带来额外的负 担,因此fork 的时候子进程不拷贝父进程的页表等信息,而是与其父进程共 享,在修改的时候拷贝出一份新的进行修改,在此处COW 的主要功能是减少 额外的copy 带来的负担。对于文件系统而言,COW 是实现快照等功能的基 础,通过保留每个快照的时刻的数据而重定向新修改的数据,可以保证快照时 刻的完整数据。对于通常的文件系统,例如 ext3/4,xfs 等,写入是 modify in place 的,这样的好处是可以保证在顺序写入后修改时磁盘上的数据的连续性, 而劣势在于修改的时候面对宕机断电等意外情况,必须保证任意时刻的数据是 合法的,因此 ext3/4 和 xfs 均引入了日志机制(ext3 使用到了 JBD),在写入数据 的时候记入额外的信息来保障数据可以恢复,随之带来的则是一次数据的写入 可能会引发若干次的日志写入操作,而日志的存储区通常与数据存储区是分开 的,这就带来了磁盘额外的 seek 操作,影响性能。ZFS 和 Btrfs 等文件系统采 取了另外一种处理办法,即对所有的数据修改均采用 COW 的办法,这样可以 保证磁盘上的数据时刻均是完整的,不必记录额外的日志,这里有一个关于各 种使用 COW 文件系统的性能对比,采用 COW 的劣势在于处理随机写后顺序 读取的情况,对于 modify in place 的文件系统,数据在磁盘上仍是连续存储 的,而 ZFS 则由于 COW 机制,随机更新的数据已经散落在磁盘上的各处,后 续的顺序读取则不必要的引入了多余的 seek 操作。 事务模型(Transactional Model)是从关系型数据库中借鉴而来的概念,对文 件系统而言指的是保证一组操作的原子性,即要么成功,要么失败,不存在中 间状态,并且各个 transaction 之间是隔离的,互不影响。ext3/4,xfs 的日志实 现和 ZFS/BTRFS 的实现均采用了事务的模型,关于 ZFS 的实现将在后文中说 明,此处需要注意的是,即便使用了事务模型,也不一定能保证用户数据逻辑 上的完整性,因为只有用户接触到的最上层应用才能确保数据逻辑上的完成 性。对于数据库而言是用户接触的最上层应用,而文件系统通常是作为其他应
用软件存储数据的仓库,事务模型只能保证文件系统在异常情况下其内部逻辑 的正确性,而用户数据逻辑上的正确性仍需要自己保证。 3. 端到端的数据安全性 ZFS 的主要设计者之一 Jeff Bonwick 写过一篇博文《ZFS End-to-End Data Integrity》,概要性的说明了 ZFS 如何保证其数据的安全性。关于“端到端的数 据安全性”笔者曾与一位网友进行过讨论,在这里而言这个概念是指从 ZFS 接 收到数据开始到调用内核中各个不同硬件设备注册的驱动写入数据之间的过 程,对于之前或者之后的过程,由于软件分层次的限制,ZFS 无法得知上层应 用传输的数据的正确性和硬件设备驱动、firmware 没有 bug,故无法保证数据 的安全性。 ZFS 的数据安全性主要通过 RAID,checksum 校验,多副本(ditto blocks) 数据冗余的方法保证,分别介绍如下: 1. RAID:ZFS 的卷管理器功能实现了 RAID 0/1/10,RAID Z(RAID 5)/Z2(RAID 6)/Z3 多个级别的 RAID 功能 ,其中 RAID1/10,RAID Z/Z2/Z3 有对数据的保护功能,RAID 1/10 比较常见,RAIDZ/Z2/Z3 则是 ZFS 引入的 raid 级别,RAIDZ 相当于 RAID 5 实现,但没有 RAID 5 存在 的 write hole ,RAID Z 类似与 RAID 5,支持一块盘损坏情况下数据的恢 复,RAID Z2 存储了两套校验码,允许两块盘损坏情况下数据的恢复,同 理,RAID Z3 支持三块盘损坏情况下数据的恢复。 2. checksum 校验: 通常的 ext3/4,xfs 默认数据写入磁盘之后,读出的数据和 写入的数据是相同的,而在大规模的集群中,silent corruption 是极其常见 的情况,而此类文件系统无法判断出此类错误,当用户发现数据损坏时为 时已晚。为了解决这个问题,ZFS 为所有写入磁盘的数据都生成了 checksum,checksum 算法基于 Fletcher 或者 SHA256,每块数据生成的校 验值存储不是存在数据块内部(这是一个先有鸡还是先有蛋的问题),而是 在指向该块数据的指针中,接下来 ZFS 也对此指针生成 checksum,记录 在指向此指针的指针中,依次类推,ZFS 的 checksum 向上递归至文件系 统的根节点,根节点也生成了 checksum 并存储了多份,形成了一颗 hash
tree。在读取数据的过程中,zfs 会对读取到的数据重新生成校验值,和存 储在父节点中的校验值进行对比,如果相同,则证明数据正确,否则出现 了 silent corruption 的情况,此时如果使用了 RAID 或者是数据存储了多 份,ZFS 会使用别的正确的数据修复错误的这个版本,如果没有 RAID 或 者所有版本均存在错误,ZFS 会报告错误。 3. 多副本数据冗余:用户可以设置 ZFS 中每份数据存储的份数,最多为 3 份,而 ZFS 默认会为文件系统的元数据在 zpool 的多块磁盘上存储多份, 避免这些关键数据的损坏带来的更为严重的后果。 4. online fsck:常见的各种 Unix 文件系统都提供了 fsck 工具,用以检测文件 系统内部可能存在的数据错误情况,而这种操作需要文件系统处于 offline 的状态,而 zfs 的 scrub(擦洗)功能允许文件系统在 online 的情况下进行 fsck 工作。并且通常的 fsck 工具只检查元数据而非数据,而 ZFS 的 scrub 功能检查包括数据、元数据在内的所有数据。ZFS Best Practices Guide 建议 对于使用企业级硬盘的服务器,每月进行一次 scrub 操作,而对于桌面级 磁盘,建议每周执行一次 scrub 操作。 5. 高效的快照功能:由于 ZFS 采用的 COW 机制,每次的写入或者是更新均不 会影响到磁盘上已有的数据,也就是说,如果必要的话,ZFS 可以记录下每次 写入/更新的操作内容,这是实现快照功能的基础,实际的快照功能实现只是在 其中选择一个从 ZFS 文件系统角度而言完整的事务作为快照点。笔者曾经使用 过 linux 下的 LVM 卷管理器,LVM 卷管理器支持快照功能,在同样的硬件环 境和用例情况下对二者的快照功能进行对比测试,lvm 打开快照功能之后,数 据更新写入性能下降到原来的 1/6,对比 zfs 创建快照之后的更新写性能,下降 约 15%,发现有少量读取 io,相比 lvm 中 kernel 的 kcopyd 线程有大量的读取 io,由于 ZFS 延迟合并了写入,并且判断出是对于旧有整个 block 的更新,所 以就不需要读取旧有的数据,更新旧有元数据就可以了,但是由于 LVM 工作 在 IO 栈的 device mapper 层,也没有对 fs 加 hook 区分,无法从细粒度层面上 对 block 写入进行感知和优化,这里有对于 lvm 使用中需要注意问题的详尽描
述。lvm 的 snapshot 功能直到最近才加入了对于递归快照的支持,而对于 ZFS 来说,实现递归快照并不会带来更多的复杂度。 基于高效的快照实现,ZFS 实现了快照数据的发送(send)和接收(receive)功 能,通过此功能,ZFS 可以高效的实现离线异地数据同步的功能,得益于 COW 机制,ZFS 可以快速的计算出来自于同一个 ZFS 文件系统实例的两个快 照之间修改的数据,dump 出文件发送到远端进行合并,而不必使用 rsync 来 计算所有文件的数据块的校验值进而同步数据的办法。 6. 自适应字节序功能: 从 5 中的描述也可以看出,ZFS 的数据可以在不同的平 台(主要是由 CPU 的大小端决定)导入和导出。 7.高效的缓存管理功能: 对于文件系统而言,除非是sync 写入的或者OS 内存 紧张的状态(在linux 下由dirty_ratio 参数控制),否则数据是首先写入文件系统 缓存,之后由文件系统或者操作系统的刷新线程(对于linux 2.6.32 以上内核为 backing device 的flush 线程,低于此版本为pdflush 线程)异步写入的,由此可见 缓存的实现是文件系统写性能的决定性因素之一。ZFS 作为一个革新的文件系 统,实现了自己的一些缓存替换算法,但为了保持与原有 OS 组件的兼容性, 而又不损失性能,ZFS 实现了自己的 page cache 功能,其他文件系统,例如 UFS 则继续使用旧版本的 page cache,ZFS 采用了 Adaptive Replacement Cache 缓存替换算法,取得了较好的性能。ARC 相当于 CPU 的 L1 Cache,使 用内存实现,因此存储的数据有限,ZFS 类似 CPU 的 L2 Cache,包括两个部 分:L2ARC 和 ZIL(ZFS Intent Log). L2ARC 是读缓存,存储在 L2ARC 的数 据是可以随时丢弃掉,从磁盘获取到的干净数据,而 ZIL 中存储的则是缓存的 脏数据,需要写入到磁盘,通常 ZIL 中缓存的都是需要同步写入的数据,ZIL 将需要同步写入的数据缓存起来,并在合适的时机按照一个事务组批量异步写 入。为了保证数据的安全性,写入 ZIL 的数据都会记录日志,此日志只有在恢 复的过程中才会读取,使用 ZIL 可以显著提高 NFS 和数据库应用的性能。类 似与 CPU 的 Cache 分层中容量递增,读写速度递减的规则,ZFS 通常使用 SSD 作为 L2ARC 和 ZIL。
8.可变的 block size :由于早期的磁盘物理参数限制,在各类*nix 系统中,磁盘 sector 的大小通常定义为 512 字节,文件系统分配空间的最小 block size 也定义 为了 512 字节。随着 Advanced Format 的出现,磁盘的 sector 可以做到 4KB 甚 至更大,更大的 sector 在存储大文件时带来更好的性能,而在许多*nix 系统 中,这个常量是 hard coded 的,修改起来并不容易,ZFS 支持从 512 字节到 128KB 大小的 block size,针对各种不同的应用环境调优选择,以达到更高的性 能。 9.数据去重功能: 数据去重功能是现在各种中高端存储设备的必备功能之一,甚 至有不少备份软件也内置了数据去重的功能,通过使用 SHA256 等特征较好的 hash 算法计算数据的指纹,在写入的过程中比对指纹,相同的数据只存储一份 进而提高了存储利用率。ZFS 的数据去重功能相当消耗内存,因此通常使用 7 中描述的 L2ARC 来存储数据指纹。笔者曾从事了两年多的数据消冗去重文件 系统的研发和设计工作,从个人的角度来看 ZFS 的数据去重功能实现还有很多 提高的余地,这点将在后文代码分析的过程中详细说明。 10.其他的功能特点: ZFS 支持对数据的压缩,目前支持 LZJB 和 ZIP 两种压缩 算法。支持 deadline 模式下的 IO 优先级调度,这点对于一些延时敏感的应用来 说相当重要。支持读取时的数据预读功能,支持高效的 IO 请求排序和汇聚,支 持按照用户和文件系统实例的磁盘限额功能等,最新版本的 ZFS 支持了透明的 数据压缩功能,并且使用了非对称的加密算法提高安全级别 2. ZFS 特性解析 2.1 ZFS COW (Copy On Write) 首先说下 ZFS 的 copy on write 这个技术并不复杂,看下图比较清晰,
- 图-1: 可以看到 uberblock 实际上是 Merkle Tree 的 root. 它记录了文件系 统的所有状态,当检索一个数据块的时候, 会从 uberblock 这里一路往下查 找 metadata block 同时比较 checksum, 直到找到对应的数据块。 - 图-2: 当写一个新的 block 时,没有 performance 的影响,当修改一个旧 的 block 时,需要先 copy 一份, 实际上会带来一些 performance 的问题, 实 际上所有的 metadata 和 checksum 都是需要复制新建。 但 COW 和 Transaction 技术一起,可以对数据的一致性得到比较好的保护。 - 图-3: 数据已经写入,上层的 metadata 和 checksum 的数据也已经修改 好,但 uberblock 还没被更新,这个时候断电重新启动,数据不会丢失,我 们仍然可用找到修改的数据, 然后将 uberblock 原子的更新。 - 图-4: uberblock 是通过原子的方式,所有绿色的部分都已经更新。 COW 带来另一个好处是 Snapshot,Replication 非常方便, 如下图:
分享到:
收藏