ZFS使用和学习笔记

近日,笔者在自己的一台服务器上,尝试使用了ZFS文件系统,觉得有很多需要记录、思考和分享的内容,遂著文记录之。

关于ZFS

ZFS(Zettabyte File System,Z比特文件系统), Zetta,中文"泽",表示2的70次方,大概的意思是这个文件系统的容量是Z级别的。但实际这并不是一个精确的数字,只是为了表示其容量非常大(大到荒谬的程度,我们后面有详细讨论)。

zfs最早由SUN为系统公司开发,原来只是一个私有的软件,是作为Solaris操作系统的一个部分。项目开始于2001年,2006年作为OpenSolaris系统的核心文件系统,可以看成为其正式发布和部署。几乎同时,作为配套的开源项目,被移植到FreeBSD和Linux系统中。后来SUN被Oracle收购,zfs转为闭源。2013年开源社区在OpenSolaris的基础上建立OpenZFS项目开始继续发展,所以现在的zfs系统的主流实现就是OpenZFS系统。由于这些过往,虽然zfs的技术非常先进和优秀,但主要由于软件协议冲突的问题(zfs主要使用CCDL开源协议),加之Linus并不信任Oracle(Don't Use ZFS on Linux: Linus Torvalds),并且拒绝将zfs引入Linux内核,这在一定程度上影响了这项技术的发展和普及。

抛开上面的问题,其实在技术上而言,ZFS是一种非常理想的文件系统,除了惊人的容量之外,具有很多先进和高级的特性,很难想象这竟然是在2000年代初,互联网技术发展的初级阶段,就设计和产生的技术,所以它在行业和专业上的评价,是非常高的。这些特性包括:

  • 支持非常大的文件和文件系统, zfs其实是一种128位的文件系统
  • 支持RAID-Z冗余存储,类似RAID-5,可以通过奇偶校验恢复数据
  • 强大的校验和数据完整性保护,所有数据都经过校验和校验
  • 内置快照和克隆功能,可以轻松完成备份和恢复
  • 具有优秀的扩展性,存储池可以方便扩展
  • 可压缩数据以节省空间
  • 支持动态条带化,提高性能。

总之,zfs是一个非常先进和高效的数据存储文件系统和服务,具有很多适合大数据存储的优点。但也存在相对复杂,占用内存和资源较多等缺点,但笔者觉得这些都不是它的核心问题所在,后面我们会讨论到相关的内容。

容量

zfs的容量,是"泽"作为基本单位的。关于这个计量单位,普通人甚至很多专业人士也是没有概念的。我们刚好可以先使用下面这个表格,来复习一下计算机的存储记录单位。

中文单位 简称 英文单位 英文简称 进率
比特 bit b 0.125
字节 字节 Byte B 1
千字节 千字节 KiloByte KB 2^10
兆字节 MegaByte M 2^20
吉字节 GigaByte G 2^30
太字节 TeraByte T 2^40
拍字节 GigaByte P 2^50
艾字节 ExaByte E 2^60
泽字节 ZettaByte Z 2^70
尧字节 YottaByte Y 2^80

参考上表,熟悉计算机系统的人士应该知道,我们现在(2023年)的技术发展阶段,单一普通主流的硬件系统,内存的主要单位一般是G,硬盘的单位一般是T。也就是说,我们现在日常对于存储的使用,离zfs的能力,还差了七八个数量级,可以说是永远也用不完。

注意,这里指的是"单一"的文件系统。如果是所有的信息处理系统加起来呢?这里有一个报告分析数据表明,2021年全球出货的存储系统,能够提供的总容量约为: 858Exabyte,也就是说,竟然还不到一个"Z"。

而且,还要考虑到,经过一段时间的高速发展,现有的信息系统的应用场景已经相对固化,对于存储的需求的扩展需求,基本上是一个线性的,并且增长速率也在逐渐变慢。所以,在理论上而言,在现在和可以预见的将来,人类是可以使用单一的zfs系统,来存储和处理所有的数据和信息的。这个和IPv6的情况有点像。

另外,这里还有一个非常有趣的角度。zfs项目领导Bonwick说过一句话:

"要填满一个128位的文件系统,将耗尽地球上所有存储设备。除非你拥有煮沸整个海洋的能量,不然你不可能将其填满"。

前一句可能还好理解,只是说明zfs文件系统容量之大;后一句的格局就有点高了,其实在说明一个信息论的重要论点:"信息即是能量"。信息的本质是在于消除不确定性,所以信息能够代表某些确定性。越复杂的事物,所需要表达确定性的信息熵就越大。我们现在主要使用的信息处理工具是基于冯诺依曼架构的电子计算机系统,要表达和处理信息就需要移动电子,就需要背后驱动电子运动和建立势能的能量。从这个角度,要迁移2^128位数据的信息(比如写入磁盘),确实需要一个非常巨大的能量,并且在现有的技术条件下是不现实的。这里需要注意,虽然zfs是按照128位文件系统设计的,但不代表zfs的容量就是2^128,所以,完全的操作zfs,还是有一点点可能的。

关于具体需要的能量,经过对claude的咨询和简单计算,它提供的信息如下:

  • 地球上所有的水的容量,大概是1.34万亿吨,
  • 使用现有普通的机械式硬盘,写入1bit的信息,大约需要1nJ(纳焦耳)的能量
  • 写入2^128bit,需要2.7x10^30焦耳
  • 水的蒸发能约为2256.7kJ/kg
  • 可以蒸发的水为 1.2x10^21吨,即1.2万亿亿吨
  • 所谓蒸干海水的说法,还真的是有道理的!

在技术设计和规划而言,zfs在容量方面的技术指标如下:

  • 16E: 最大单一文件大小
  • 2^48: 目录中子项目数量
  • 16E:项目属性大小
  • 2^56: 文件的属性数量
  • 2^128: 最大存储池大小
  • 2^64: 存储池中设备数量限制
  • 2^64: 存储池中文件系统数量限制
  • 2^64: 系统中存储池数量限制

这...,应该不会有人抱怨什么了吧。

系统架构

和传统(90年代发展起来)的文件系统相比,zfs具有很多先进和高级的特性,让人觉得那不应该是同一时代的产品。笔者觉得,zfs的最大的特点和优势其实是其设计理念和实现能力。zfs从开始设计的时候,就已经不是一个单纯的文件系统,而是是一个综合了文件系统(File System)、设备管理(Device Manage)和RAID控制器(RAID Controller)的现代化综合性存储服务软件。

这里借用一下其系统架构示意图:

具体细节我们不用追究,只需要理解zfs并不是简单的文件系统,而是包括:

  • 设备管理:可以组织和控制磁盘等存储设备,并提供存储的可扩展性
  • 文件系统:提供标准文件系统应当具备的基本功能和操作模式
  • 数据完整可靠:通过事务、日志、冗余和故障恢复等特性,提供数据的完整性和系统服务的可靠性
  • 性能优化:充分使用缓存架构、减少和优化数据操作、数据压缩等方式,提高和优化系统性能
  • 简化管理:系统应当简单易用,并能够自动调整工作状态,减少和降低运维工作和成本
  • 业务特性:提供通用化,抽象化的更丰富的业务特性如加密、高效数据备份和传输等

这里我们就可以重复了解到,一个现代化的文件系统,或者上升到存储服务系统的层面上,应该具备的特性和可以使用的技术方案,而zfs,就是一个典型和优秀的代表。

下面,我们就来研究一下,zfs是如何做到的。

核心技术和特性

zfs通过以下一些主要和核心的技术,来构建一个"现代化"和"先进"的存储系统和服务。其最终目标是达成存储服务的可靠、灵活和高效。其中,可靠性主要体现在存储信息的完整、可靠和安全,存储服务的可用和稳定等;灵活性主要指系统的可扩展性好,配置和调整操作的灵活和方便;高效主要是管理的便捷,系统服务的性能优异,资源使用的高效,部署和使用成本低廉。

存储池(zpool)

zfs是比较早提出和实现"存储池"和"虚拟化设备"概念的文件系统。传统文件系统通常需要驻留于单独设备或者需要一个卷管理系统去使用一个以上的设备,而zfs是完全建立在虚拟的,被称为zpool的存储池之上。zfs存储池可以由若干虚拟设备(Virtual Devices,vdevs)组成。这些虚拟设备可以是多种形态,如原始磁盘或者分区,也可能是一个RAID1镜像设备,或是非标准RAID等级的多磁盘组(后面会提到的RAID-Z)。zpool可以基于这些虚拟设备和它们的组合几乎无限而动态的扩展,从而提供可以动态扩展的存储容量和能力。

zfs为存储池提供了完整的生命周期管理。zfs提供了命令行工具可以实现以下管理任务:

  • 创建和删除存储池
  • 增加设备或者设备组
  • 向设备组增加和卸载设备
  • 替换设备
  • 增加或者移除设备
  • 存储池上线和离线
  • 存储池更新
  • 存储池状态和设备列表
  • 设置设备用途
  • ...

Linux内置的逻辑卷管理程序(LVM)也有存储池的相关概念和操作方式,但笔者觉得无论在功能的丰富和完善,还是简洁易用方面,和zfs都没有办法相比。

存储池是zfs的核心和基础。基于zpool,zfs可以进一步创建轻量化的文件系统和逻辑卷,来为系统和应用提供灵活高效的存储服务。

轻量文件系统(File System)和特性

zfs中的文件系统,更多是从操作系统和应用的角度出发而言的,所以称为轻量级的文件系统。笔者理解,这里的文件系统,其实就是其他文件系统中"卷"(Volumn)或者分区的概念。但这个文件系统更加灵活和动态,类似于普通文件系统目录的组织方式,配置和使用也更为方便。

这些文件系统基于存储池构建,以文件系统为单位,zfs可以提供挂载点,系统特性配置和其他管理特性。神奇的是zfs文件系统的使用无需初始化或者格式化的过程,也没有所谓的分区或者文件系统格式选择,创建完成之后就可以使用。此外由于其底层基于存储池,其容量就是存储池的容量,可以动态的扩展,使用起来非常方便灵活。

在zfs的文件系统之上,可以提供很多丰富的功能和特性,这里主要例举它们在应用方面的内容,部分技术细节和原理,在后面的章节进行讨论。

  • 磁盘配额和保留空间(Quota/Reservation)

用户可以为文件系统配置磁盘配额和保留空间。前者可以限制某些应用或者用户不会过分使用存储空间;而后者则可以保护某些应用或者用户可以有适当的资源可以使用。

  • 文件系统压缩(Compress)

zfs文件系统支持透明的压缩功能,对于一些使用场景(日志、配置、文档、代码等),可以大幅度的节省实际占用的存储空间。zfs默认支持多种压缩算法,现在的优先默认算法是LZ4。对于常见的系统日志,如果使用zfs压缩文件系统来进行存储,可以节省大约50%以上的存储空间。此外,zfs的数据压缩功能设计和实现的相当高效,对性能的影响十分轻微。

  • 快照和复制(Snap/Clone)

关于快照和复制的技术原理,前面已经有所叙述。从应用的角度而言,就是可以随时创建一个当时的文件系统的只读副本。然后在后续可以将文件系统回滚到某个快照状态上。由于快照基于写入时复制技术(后面会讨论),快照几乎不会占用额外的磁盘空间。而且,多次快照,系统只记录其中增量的数据,提高了存储空间使用的效率。此外,快照时会固化所引用的数据块,可以防止数据被覆盖,有利于数据恢复和备份。

复制和快照类似,但创建的是可读写的副本。复制只能从快照进行创建,创建后的初始内容和此快照的数据集相同。

  • 快照发送(Send)

zfs可以将快照数据,使用数据流的方式进行传输。通常发送功能在存储池之间使用。但这个流可其实是操作系统标准数据流,也就是说,甚至可以结合如SSH等协议,进行远程数据的发送和接收。这样,这个特性就可以应用在如系统和数据备份,虚拟机迁移等场景。

跨主机的快照发送,可以使用如下的命令,让我们了解其工作过程和场景:

zfs send datapool/ | ssh otherserver zfs recv backuppool/backup

  • 数据块去重(deduplication)

zfs支持基于数据块的重复数据删除。如果多个文件具有相同的数据块,则zfs将会在系统中只实际存储一份数据(块)。系统将会自动维护文件和数据块之间的引用关系,这一过程对于用户而言是完全透明的。数据块去重会使用一个"重复数据删除表",当然也占用一部分磁盘和内存空间和计算性能,用户需要根据自己的应用场景,评估此功能的适用性和对性能的影响。这个功能比较适合用于冷数据和备份数据的场合。

  • 可变数据块尺寸

zfs使用可变大小的块,默认为128KB。管理员可以为文件系统设置最大数据块的大小。

zfs的可变大小的块与BtrFS和Ext4的extent不同。在zfs中,数据块大小"可变"的意思是,在一个文件中所有数据块的逻辑长度是相同的,但不同文件的块大小可以不同。因此ZFS可以用直接映射(Direct Map)的方式来搜索间接块的数据指针数组(blkptr)。BtrFS和Ext4的extent方式在同一个文件中每个数据块的大小都可以不相同,因此需要用B+树或类似的方式来组织间接块的数据。

虽然直接映射方式比B+树,但其缺点也非常明显,如:元数据开销过大、顺序IO的大文件性能不好、删除比较慢等等,因此在现代文件系统中映射方式逐渐被extent变长块取代。

数据块可变大小的意义在于,对于不同大小和类型的文件,可以找到比较合适的块大小。对于小文件,可以使用更小的块,提高存储空间的利用效率;而对于大文件,可以显著减少块信息检索和操作的次数,提高I/O的性能;关键是这个调整都是根据算法自动完成的,不需要人工决策和干预,对于大型系统非常重要。

如果数据压缩(LZJB)被启用,可变块大小需要被用到。如果一个数据块可被压缩至一个更小的数据块,则小的数据块将使用更少的存储和提高吞吐量(代价是增加CPU压缩和解压缩的负担)。

  • 文件共享

zfs内置了对NFS,SMB和iSCSI共享的支持。实际的文件共享服务并不是由zfs提供,而是由外部标准的系统模块提供(不同操作系统上的实现可能有差异)。zfs只是提供了方便的配置和管理功能,如可以直接将文件系统设置为共享,然后zfs服务就会配置外部服务来提供网络文件共享。

如下面的命令就可以启用SMB协议,来共享一个zfs文件系统:

$ zfs share -o share.smb=on pool/dataset%share-name

  • 文件系统加密

OpenZFS支持文件系统加密。和文件和应用级别的加密不同,zfs加密一般是文件系统级别的。通过对文件系统内的数据块进行加密,它可以有效保护静态数据的隐私、满足安全合规要求、实现多租户隔离等目标,可以适用于更复杂的应用场景。

最简单的模式可以是只使用一个密码来保护文件系统:

shell 复制代码
# zfs create -o encryption=on tank/home/darren
Enter passphrase for 'tank/home/darren': xxxxxxx
Enter again: xxxxxxxx

zfs默认使用AES-128CCM作为标准加密算法。当然完整和完善的zfs加密体系是包括相关的密钥管理的。显然,在日常的文件操作时,对文件系统数据块进行实时的加解密操作,会带来一些系统负担,但由于现代硬件系统日益强大的计算性能和硬件级别的AES加速,这个性能衰减在较新的硬件平台上并没有太大的影响。一般认为这个加解密操作,会对文件存取操作,带来大约10%~15%的性能损失。

RAID(RAID-Z)

前面已经简单提到,zfs的存储池,可以由各种形态的虚拟设备(磁盘)构成。可以是简单的单一磁盘、磁盘镜像和RAID-Z磁盘阵列等方式。其中,zfs的精髓和核心就包括这个RAID-Z磁盘阵列技术。

我们都很熟悉,RAID(Redundant Array Of Inexpensive Disks,廉价磁盘冗余阵列)是最常用的存储系统技术方案。它通过磁盘冗余和相应的算法和管理,可以提供存储系统的高性能和高可用性。主流的RAID技术都是基于硬件就是RAID HBA(主机适配器)实现的,它是一个硬件板块,通常插到主板的PCI-E总线插槽之上。这个卡可以通过标准接口如SAS或者SATA连接多个磁盘,并将它们配置成为磁盘阵列,可选的阵列构成方法有很多,常用的如镜像(RAID1)或者分布式循环冗余校验(RAID5)。配置完成后,对于操作系统而言,看到和使用的是这个阵列所表示的单一逻辑磁盘,而且这个磁盘(其实是阵列)可以透明的提供更高的性能(多个磁盘并发访问和负载均衡)和高可用性(磁盘失效后可以替换并且重构阵列),由于只需要配置和管理单一逻辑磁盘,可以大大简化在系统端大量磁盘的管理和应用(图为RAID和各种级别)。

看起来很完美? 其实不然。

长期的实践表明,基于硬件的RAID技术方案也有很多问题。首先就是灵活性比较差,如果增加一块磁盘,需要停机,然后在系统启动之前进行配置,硬盘重新配置和重组也非常麻烦;但最让人诟病的是如果RAID卡坏了,相关配置信息就会丢失,所有磁盘在逻辑上都会失效;另外其重构的操作的低效和对性能的影响等等,都是很大的问题;最后,本来RAID技术的设计初衷是"廉价",意思就是单一的大容量高性能磁盘太贵,可以使用大量小容量的磁盘组合起来,也可以达到相同的效果。但往往由于功能和性能要求越来越高,现在的RAID卡附加了很多控制芯片、算法、接口、缓存、电池等等,再加上管理、运维和业务终端的成本,总的成本其实更为高昂。特别是云计算和"存储即服务"的发展趋势之下,其弊端日渐明显。人们需要一种可以在运行状态下就可以方便灵活的"动态的"存储系统,同时又能提供相应的高性能和高可用的技术方案,即所谓"软件定义存储",这应当只能在操作系统的级别来实现。

为此,zfs提供了基于软件的RAID解决方案,称为RAID-Z。技术上而言,RAID的工作原理其实就是简单的数据循环冗余校验算法,算法并不复杂,本身也是非常经典而成熟的,在操作系统或者服务层面使用软件实现并没有太大的障碍和性能影响,反而可以简化在硬件层面的架构和损耗。zfs使用的RAID技术在逻辑和本质上其实和原来的并没有不同,但在具体实现集成综合了文件系统和虚拟磁盘等方面考虑,在整体上有一些改进和优化。

  • 动态条带化

传统的硬件RAID,数据的条带化(数据块在多个磁盘上的分布方式)是固定的。比如RAID5,就是数据分布在n-1个磁盘上,另留出一个磁盘作为校验信息。而zfs则实现了在存储池内的动态条带化。这个"动态"体现在,当新的设备被加入到zpool中的时候,条带宽度会自动扩展以包含这些设备。这使得存储池中的所有磁盘都被用到,同时负载被平摊到所有的磁盘上,从而扩展整个存储池的数据吞吐能量。。

  • 多个RAID级别

RAID-Z也可以选择多个级别。包括Z、Z2和Z3。它们提供不同级别的失效保护。如Z3可以运行磁盘组中有三块硬盘同时失效,也可以保证不中断服务(但会降低性能)。

  • 备用设备(Spare)

RAID-Z中可以指定某些设备作为备用设备,这样当某些磁盘失效时,备用设备可以自动进行替换和重建,从而使磁盘失效对服务的影响最小。如果没有备用设备,则需要运维人员紧密监控系统运行状态,并且在失效时,发现失效设备,并手动进行替换。

这样,RAID-Z在软件层面上,实现了非常灵活而且方便的RAID特性,为构建基于RAID-Z的存储池提供了良好的基础。

  • 智能重构(Intelligent Resilvering)

Resilvering(重构)是RAID系统,在磁盘失效时,通过剩余的磁盘数据重新构建失效磁盘上的数据。这个特性,是所有RAID系统的核心和价值所在。

但遗憾的是,现在大部分RAID系统,包括那些硬件实现的系统,在重构操作的实现上,都不是很理想。根据RAID运作的基本原理,它们通常都使用"全盘恢复"的方式,以磁盘作为单位,来进行重构。这个工作通常需要的时间比较长,并且在重构期间会非常影响整个磁盘阵列的性能。

针对以上不足,zfs提出了"智能重构"的优化方案,它能够跟踪哪些数据发生了变化,并只针对变化的数据进行重构,而不是笨拙的扫描整个磁盘;另外它还可以监控磁盘和系统的工作负载,动态的控制和调整重构的速度,以减少对正常I/O性能的影响。这样就可以大大减少恢复时间,同时减轻对系统正常运行的影响。

写入时复制(Copy On Write,COW)事务模型

zfs作为一个原本为企业级应用设计的存储系统,保证数据的完整和可靠,是一个很重要的设计目标。因此,其被设计成为一个"事务型"的文件系统。也就是说,文件系统在文件操作时,能够保证这个操作行为的可靠和完整,绝不会出现由于一些外部因素而导致的文件操作错误和数据冲突的情况。

为此,zfs采用写入时复制事务对象模型。和以前的文件系统不同,如果要修改一个已经存在的文件,zfs在写入新数据的时候,并不直接覆盖已有的数据块,而是为修改的数据分配一个新的块和地址。当然,任何引用此块的元数据块都被重新读取、重新分配和重写。为减少该过程的开销,多次读写更新会被归纳为一个事件组,在需要同步写入语义时会使用ZIL(目的日志)写入缓存,而这些块会与校验和一同编入Merkle树中。

这个事务模型的实现方式,不仅仅可以保证数据的可靠完整之外,还可以提供很多额外的特性,包括快照、克隆和版本管理等等,从而在业务和应用支持上提供了更丰富的功能和扩展性。

例如,当ZFS写入新数据时,可以保留包含旧数据的块,因而能够维护文件系统的快照版本。ZFS快照具备一致性(快照基于单个时间点反映整个数据)。而因为组合快照的所有数据都会被储存,且整个存储池通常每小时会进行几次快照,所以快照的创建速度非常快。任何未变动的数据会在文件系统及其快照之间进行共享,因此也具备空间高效性。快照本质上是只读的,确保在创建后快照不会被修改。快照可以被整个恢复,也可以恢复快照中的某些文件或目录。

ZFS也可以创建可写快照("克隆"),让两个独立的文件系统共享一组块。对克隆文件系统的修改都会创建新的数据块以反映这些更改。但是无论存在多少个克隆,未变动的块仍然会被共享。这是写入时复制原则的实施方式。

当然,写入时复制也会带来一些代价。比如文件碎片化,过期无效数据对磁盘空间的占用等等。但总体而言,随着处理性能和存储成本的降低,这些问题的影响也越来越小。

数据校验(Data Integrity)

除了COW事务模型之外,zfs还使用了很多技术手段,来保证数据的存储安全和完整。

zfs中,所有数据和元数据都通过用户可选择的校验和算法进行验证(类似于fsck工具,但更强大)。在传统设计中,数据校验通常是在数据块内进行的,但某些故障可能导致数据关联不正确但没有校验和错误,如向错误位置写入完整的块等,这种情况就会导致在应用层面的文件逻辑损坏。而和传统文件系统有所差异,zfs使用跨数据块校验和(Disk Block Checksums)的方式,可确保检测到这些故障并可以正常地从其中进行恢复。此外,zfs还会提供自我修复数据(Self Heathing),它支持存储池具有各种级别的数据冗余性。检测到坏的数据块时,zfs会从另一个冗余副本中提取正确的数据,而且会用正确的数据替换错误的数据。而且,所有校验和验证与数据恢复都是在文件系统层执行的,并且对应用程序是透明的。

执行日志(ZFS Intent Log,ZIL)

日志系统,也是一个现代文件系统的典型特性。和日志在数据库技术中的作用类似,它主要用于故障恢复时,保持数据可恢复和完整性。

zfs可以为存储池额外设置一个专门用于日志的设备组。来满足POSIX对于同步实务操作的需求。在某些场景下,如数据库日志操作和NFS的 fsync系统调用,这一特性可以更好的支撑相关的业务和应用系统。

流水线I/O(Pipeline I/O)

zfs可以将大量磁盘的I/O操作,编排成为更加高效的方式来执行。这在深层次上涉及到硬盘的工作原理和数据的组织方式。比如有两个操作需要读写在不同扇区位置上的数据块,zfs就可以控制磁头优先访问不同文件但在同一扇区或者扇环上的数据块,然后才操作磁头转换到另外的扇环之上,这一可以减少磁头运动的幅度和次数,从而提高操作效率。

这个功能的设计确实非常高超和巧妙,但关于这一点,笔者其实是有一些疑问的。首先在一个虚拟设备的环境中,系统是如何知道其物理实现的呢?再者,现代化的存储设备,已经逐渐减少碟片化的硬盘的使用,而转向SSD包括M.2等存储技术,其工作原理已经完全改变,已经完全没有磁头需要操作了,这个特性的意义又体现在何处呢。所以,笔者觉得这个特性本质上不应当是一个文件系统需要关心的问题。

ARC和L2ARC

和传统的文件系统的定位和设计思路不同。zfs主要为高性能的数据存储和服务而设计,而在任何高性能计算机系统中,合理设计和使用缓存都是提高性能的最重要的方式之一。zfs也不例外,它在系统内部规划和实现了提高存储性能的缓存机制,称为ARC(Adaptive Replacment Cache,自适应替换高速缓存)。而一般的文件系统的实现和设计并不涉及这部分的内容,通常交给操作系统来进行处理。

ARC的设计也和一般操作系统的缓存实现方案稍有差异。通用的缓存算法通常为LRU(Least Recently Used,最近使用)淘汰算法。针对于文件访问的使用特点,zfs提出了ARC,它结合了LRU和LFU(Least Frequestly Used,最不常用)两者淘汰算法,并进行了一些改进和扩展,能够有效综合处理缓存最近的块请求和最频繁的块请求,从而提供性能更好的文件存储服务。ARC是zfs系统级别的特性,它可以为多个zpool提供服务。

L2ARC(二层ARC)是在ARC基础上的扩展。ARC主要使用内存进行工作,这个第二层的意思是ARC扩展并部署到读写速度很快的磁盘设备之上,如新型的M2 Nvme或者SSD磁盘上。来减轻ARC对于内存占用的压力,降低存储系统的总体成本,这个概念和操作系统中的交换空间类似。

简化管理

虽然zfs提供了如此多样和强大的功能和特性,但其使用和管理却是相当简单的。

zfs通常是作为系统服务来进行加载的。服务加载后,就可以使用相应的管理工具来开展管理工作了。zfs的核心管理工具非常精简,基本上只有两个命令行工具。zpool用于存储池和设备的管理;zfs用于文件系统的管理。

实务和操作

下面我们来通过笔者的一个简单的使用场景,来观察一下在实际的场景中,是如何使用zfs的。

  • 现状、需求、配置和规划

笔者的使用场景完全是普通家用的场景,并不是典型的企业级的存储系统的应用场景,只是为了研究和体验zfs文件系统的使用。此外,还有一个简单的业务需求,就是有大量的大文件需要下载、传输和存储,所以希望尽可能利用到有效可用的磁盘空间,并在后续可以方便的扩展存储空间(比如加一个新硬件,可以扩展到当前的存储卷中),暂时不需要考虑磁盘冗余和高可用。

基本软硬件配置如下:

  • CPU: Intel I3 7100T
  • RAM: 16G DDR4 2666
  • HD1: M.2 NVME 256
  • HD2: 1T SATA
  • OS: EndeavousOS 2023
  • Kernal: 6.5.7

磁盘使用的规划是,HD1分为两个分区,第一个容量为100G,用于安装操作系统;剩下的第二个分区的空间,和HD2,组成一个zfs存储池,并建立文件系统作为主要的工作用的空间。后期可能会增加一个磁盘,可以加入此存储池,实现无缝的空间扩展。

  • zfs系统安装

EndeavousOS是基于Arch Linux的发行版本,使用pacman作为其软件包管理工具,所以其安装方式和常见的CentOS或者Debian都略有差别。zfs不是Linux kernal的一部分,也不是标准的pacman包,而是aur包,所以通过yay安装。

yay -S zfs-linux-lts

系统安装完成后,对于用户而言,系统主要会增加一系列系统服务和两个管理工具,包括zpool和zfs命令行工具。

  • 按照需要,装载zfs系统模块(按需)

可以使用如下的指令,来装载zfs系统模块:

modprobe zfs

  • zfs启动和服务

开启,启动和查看zfs系统服务的命令如下:

systemctl enable|start|status zfs.target

shell 复制代码
[root@john-fmvb10005 ~]# systemctl status zfs.target
zfs.target - ZFS startup target
     Loaded: loaded (/usr/lib/systemd/system/zfs.target; enabled; preset: enabled)
     Active: active since Thu 2023-11-02 09:16:50 CST; 24h ago

看到这个信息,基本上zfs系统就算是正常启动了。

  • 存储池和文件系统

所有的安装和配置工作完成之后,就可以像使用常规的文件系统和文件夹一样,使用zfs挂载好的文件系统了。总体而言,感觉和使用以前的ext4没有什么差异,就和linux系统原生的文件系统一样。

这个流程大致为:

1 可以使用lsblk命令检查当前磁盘和分区情况

shell 复制代码
[root@john-fmvb10005 ~]# lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda           8:0    0 931.5G  0 disk 
nvme0n1     259:0    0 476.9G  0 disk 
├─nvme0n1p1 259:1    0  95.4G  0 part /
├─nvme0n1p2 259:2    0  15.6G  0 part [SWAP]
└─nvme0n1p3 259:3    0 365.9G  0 part 

我们可以看到系统中有两个磁盘,其中一个nvme盘是系统盘,除了安装系统之外,还空余一个分区,可以用作zfs文件系统。另一个是普通硬盘,还未作任何处理是裸盘。

2 使用第一个磁盘分区(nvme的空余分区)创建zpool, 使用 zpool crreate 命令

zpool create zdata /dev/nvme0n1p3

这时zfs会创建一个存储池,并自动将其挂载到/zdata文件夹。

3 将第二块磁盘加入存储池

zpool add zdata /dev/disk/by-id/ata-ST1000LM014-1EJ164_W772P7PH

这里使用了by-id的引用模式,因为后面可能还会加入磁盘 /sda 的磁盘标识可能会发生变化,使用by-id可以固化对此磁盘的引用,避免引用错误。

这里有一个比较奇怪的地方是zpool并没有完全使用裸盘的方式,而是将其进行了分区(留了一个8M的尾巴),并使用第一个分区用于存储池。

笔者此时只有这两块磁盘,如果有更多的磁盘,就应该可以尝试使用raidz的组织和加入方式,这些操作对于使用都是透明的,存储池容量会立即增加并且可用。

4 检查存储池, 使用 zpool status和list 命令

shell 复制代码
[root@john-fmvb10005 ~]# zpool status
  pool: zdata
 state: ONLINE
status: Some supported and requested features are not enabled on the pool.
	The pool can still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
	the pool may no longer be accessible by software that does not support
	the features. See zpool-features(7) for details.
config:
	NAME                               STATE     READ WRITE CKSUM
	zdata                              ONLINE       0     0     0
	  nvme0n1p3                        ONLINE       0     0     0
	  ata-ST1000LM014-1EJ164_W772P7PH  ONLINE       0     0     0

errors: No known data errors


[root@john-fmvb10005 ~]# zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
zdata  1.26T   637G   655G        -         -    18%    49%  1.00x    ONLINE  -

5 创建文件系统

zfs create zdata/backup

这个命令会以默认设置,创建一个文件系统,名为backup,并且会挂载到/zdata/backup位置上。zfs的文件系统,使用时的感觉就是一个卷,它体现为一个文件夹,可以作为一个管理单元,但会共享存储池空间。

  • 系统重启

zfs的配置是实时可用的。安装配置过程完全不用不用重新启动系统,也不同什么磁盘分区,格式化等等操作。但默认情况下,如果重新启动系统,可能会遇到zfs无法正常加载的情况。这时候可能需要手动操作一下。一般是确认zfs服务正常启动后,使用zpool import zdata命令和zpool upgrade命令加载zfs配置。

这部分内容由于笔者时间关系,就没有反复测试配置确认操作系统重启后,相关配置能够自动加载和恢复。

  • 版本冲突

在使用了一段时间后,笔者对操作系统进行日常的升级,这次升级涉及到内核版本的升级。然后在系统重启之后,zfs无法正常启动和加载存储池了。出现的故障,类似下面的信息:

shell 复制代码
Error: Failed to prepare transaction:
could not satisfy dependencies:
- unable to satisfy dependency 'linux=6.0.2.arch1-1' required by zfs-linux
- unable to satisfy dependency 'linux-headers=6.0.2.arch1-1' required by zfs-linux

显然,这应该是涉及zfs和linux内核兼容方面的问题。经过一段时间的努力,尝试了很多方法,都没有效果。最后笔者使用的解决是: "系统内核降级"。

我们知道,在主流发行版中,archlinux相对是比较激进的,它的版本升级的比较快,相对而言好像就不是那么稳定。其实也有一个缓解的办法,就是使用lts(Long Team Service长期服务版本)版本。我们可以使用以下命令,将当前的内核降级到lts版本:

shell 复制代码
sudo downgrade linux-lts
update-grub

降级成功完成之后,zfs就能够正常启动和工作了。

这次的问题,告诉我们zfs技术在linux社区中的地位并不是很高。很多系统的升级和维护,并没有做到进度匹配和及时。其实有很多内容,在运行上也是可以兼容的,就是由于一个版本号判断的问题,就有可能导致报错而无法运行,就需要大量的系统测试

一些问题和思考

从zfs系统设计和实现的思路,以及一些使用的经验而言,笔者对zfs的印象是非常好的。但现实情况却是这么好的技术,使用的并不广泛,从而导致其发展也比较缓慢。笔者思考,可能涉及到以下的一些因素。

  • 许可证问题

ZFS的应用受到限制,主要因素并不是技术而是商业。而是ZSF的许可证。前面已经提到,zfs技术的商业发展的过程是比较曲折的,导致到现在为止,很多相关的技术并不能做到完全的开放和开源,特别是考虑到Oracle在行业内不那么好的名声,其相关的产品多多少少受到了一些影响,并不能完全融入开源社区和文化。

  • 资源占用

ZFS另一个经常为人诟病的问题是觉得它运行时占用内存比较大,对系统硬件性能的要求也较高,这是其设计和运行的原理所决定的。考虑到其产品定位,这也是可以理解的,zfs原本为服务器运行环境而设计,内存的大小并不是一个主要的限制因素。另外随着硬件技术的发展,这个问题也得到了大大的缓解,其装备和使用成本也非常快速的降低到了可被接受的水平。通常认为要流畅的运行zfs系统,系统内存应当在8G以上,在2023年,这并不是一个问题。

  • 易用性

就笔者使用的经验而言,zfs系统的稳定性还是不错的,毕竟是为企业应用设计的。但易用性确实有点问题,影响到了它的推广和应用。

但笔者想要强调,这里的易用性,并不是对于用户而言的。从使用和后期配置的角度而言,zfs其实非常易用。不停机的存储管理、无缝无感的存储扩展、丰富的管理功能,都是非常领先和实用的。

但有可能是由于软件许可证的问题,zfs在最流行和重要的服务器操作系统Linux之上,并不是开箱可用的。需要单独安装和配置。当然,它在默认情况下,应该也没有写入Linux系统的内核。然后一些组件的配置和管理,以及问题和错误的排查,对系统管理人员的技术水平要求也比较高。这些会导致其总体的学习和使用门槛比较高。

  • 非技术竞争

如果能够很好的了解和应用zfs系统,是可能真正的实现"廉价冗余磁盘阵列,RAID"这一技术的初衷的。但在现实的世界和市场中,这就是一个"颠覆性创新"。zfs如果得到更广泛的普及和应用,它就会挤占现存庞大的硬件RAID市场,并涉及巨大的利益重新划分。作为没有强大后台的zfs技术,是很难在市场层面上直接挑战这些硬件和系统厂商的。

相关推荐
KookeeyLena51 小时前
云手机可以挂在服务器使用吗?
运维·服务器·智能手机
洛寒瑜1 小时前
【读书笔记-《30天自制操作系统》-23】Day24
开发语言·汇编·笔记·操作系统·应用程序
老汉忒cpp1 小时前
手动部署并测试内网穿透(ssh 和 nginx)
运维·服务器
有时间要学习1 小时前
Linux——应用层自定义协议与序列化
linux·服务器·网络
hardStudy_h2 小时前
Linux——常用系统设置和快捷键操作指令
linux·运维·服务器
我叫啥都行2 小时前
计算机基础知识复习9.7
运维·服务器·网络·笔记·后端
qq 1778036223 小时前
智能新时代,游戏盾守护顺畅体验
运维·服务器·网络·游戏·云计算·ddos·ip
神秘的土鸡4 小时前
Linux中使用Docker容器构建Tomcat容器完整教程
linux·运维·服务器·docker·容器·tomcat
shuxianshrng4 小时前
大气网格化精细化监管监测系统
大数据·服务器·windows·经验分享
friklogff5 小时前
【C#生态园】构建你的C#操作系统:框架选择与实践
服务器·开发语言·c#