文件系统一般有ext4、ext3、ext2、nfs、xfs等,我们在创建删除以及读写文件时基本上感知不到下面是什么文件系统类型,这是怎么让用户感知不到的呢?虽然感知不到差异,但也需要深入理解下这些文件系统的区别及其演进路线。
VFS的诞生
为了隐藏各个类型文件系统的差异,需要对待访问的文件系统对象提取通用的对象模型(比如索引节点、文件对象、分页缓存、目录条目等)和方法。VFS(Virtual Files System)虚拟文件系统应运而生,在用户进程与各种类型的Linux文件系统之间封装一个抽象接口层。有了VFS,用户进程不需要知道操作系统使用哪一类型的文件系统,用户进程不需要知道系统调用文件系统对应的方法,只要调用open(),read(),write()即可。
到底是什么类型的文件系统,上层应用进程不感知,但VFS是需要感知到的。问个问题:VFS怎么感知到的?又是怎么区分的?这里暂不探讨。
日志文件系统和非日志文件系统
不管日志文件系统还是非日志文件系统,当一个文件系统执行写操作时,Linux内核都会修改文件系统的元数据(metadata)和实际的用户数据,只是修改的顺序和修改的地方不同。
在非日志文件系统中,当一个文件系统执行写操作时,Linux内核首先改变文件系统的元数据(metadata),然后再写实际的用户数据。在修改文件系统的元数据过程中,如果操作系统由于某种原因突然崩溃,则文件系统的一致性可能会被破坏。通过检测所有的元数据,fsck进程可以修正不一致,并在下次重新启动时恢复一致性。(先打个问题:fsck如何修正不一致?元数据给回退掉嘛?此时元数据可能丢失,实际数据肯定是没有)
非日志文件系统的弊端:当文件系统具有一个巨大的卷,且需要大量的时间来完成fsck修复时,这个过程中是无法对文件系统执行操作的。
日志文件系统可以解决这个问题:在执行写数据到实际文件系统之前,先将待改变的数据写到日志区。日志区域可以放置在文件系统之上或者文件系统之外。被写入日志区域的数据称为日志记录。日志记录包括待改变文件数据的元数据和实际的文件数据。
日志文件系统的弊端:相比非日志文件系统,日志文件系统在实际用户数据写到文件系统之前写日志记录,这会导致性能开销。牺牲多少性能开销来保证较高的数据一致性,取决于在写入用户数据之前有多少信息被写入到磁盘。
非日志文件系统ext2:快速、简单的文件系统
Ext2文件系统以引导扇区开始,接下来是块组,将整个文件系统分成若干个小的块组有助于提高性能,因为将用户数据的索引节点(i-node)表和数据块更紧密地保存在磁盘盘片上,因此可以减少寻道时间。
要查找一个文件的数据块,首先要查找这个文件的索引节点。如果一个进程请求打开 /var/log/messages,kernel会解析文件路径,搜索/(根目录)的目录条目,该目录条目中有根目录下的文件和目录信息。接下来内核可以找到/var的索引节点,并且查看/var下的目录条目,该目录条目中也有/var下面文件和目录的信息。内核以此方式一直向下搜索直到找到文件的索引节点。Linux内核使用一个文件对象缓存,比如目录条目缓存或者索引节点缓存来加速查找符合条件的索引节点。一旦Linux内核找到了文件的索引节点,它会试图找到实际的用户数据块。
日志文件系统ext3
ext3和ext2主要区别是支持日志功能。ext3文件系统有5大要点:
1) 可用性(AvaiIabiIity):Ext3总是以一种一致性的方式写数据到磁盘,因此在不正常关机(意外电源故障或系统崩溃)时,服务器不需要花费太多时间检测数据的一致性,从而减小了系统恢复时间。
2) 数据完整性(Data integrity):通过mount命令显式声明日志模式data=Journal,所有数据,包括文件数据和元数据,都被写入日志中。
3) 速度(Speed):显式声明了日志模式data= wirteback,根据商业需求决定写入速度与完整性。在繁重的同步写环境下尤其注意。
4) 灵活性(FIexibiIity):现有的Ext2文件进行简单地系统升级,并且不需要重新格式化。通过tune2fs命令和编辑/etc/fstab文件,就可以轻易地将一个Ext2系统更升级为一个Ext3文件系统。注意:Ext3文件系统可以同Ext2禁用日志那样挂载。
5) 日志模式
Ext3文件系统支持3种类型的日志模式:
5.1) 全日志(journaI):元数据和实际数据均先被写入日志区,然后再写入主文件系统。该方式提供了很高的安全性,不论是元数据还是实际数据在写入日志区期间系统发生崩溃,均不影响实际的主文件系统。但该模式为实现安全性也付出了效率的代价,因为所有数据都要写入两次。
5.2) 顺序(ordered):实际数据同样被直接写入主文件系统,而元数据在实际数据写入完成后才被写入日志区。顺序模式是日志文件系统默认使用的模式。假如实际数据被写入过程中出现系统崩溃,那么修复文件系统后,元数据不变,部分实际数据被更新。
5.3) 回写(writeback):元数据被记录到日志区中,实际数据被直接写入到主文件系统。该方式能提供较好的性能。如果元数据写入日志区后出现系统崩溃,那么在文件系统恢复后,元数据和部分实际数据被更新,但恢复后的文件可能包含原先旧的垃圾数据。
以上三种模式共同的特点是,在写入主文件系统前,元数据都先记录到日志区,这样就保证了主文件系统的元数据不被破坏。另外,当文件系统恢复时,只需读取日志区中的信息即可,而无须遍历整个文件系统。
日志文件系统ext4
Ext4文件系统引入了大量新功能,共12个特性,但最重要的是对Ext3文件系统的向后和向前兼容性以及在时间戳上的改进。
1) 向后和向前兼容性
Ext4对Ext3是向前兼容的,可以将Ext3文件系统挂载为Ext4文件系统。为了充分利用Ext4的优势,必须实现文件系统的迁移,以转换和利用新的Ext4格式。还可以将Ext4挂载为 Ext3(向后兼容),但前提是Ext4文件系统不能使用区段。除了兼容性外,还可以逐步地将Ext3文件系统迁移到Ext4,意味着没有移动的旧文件可以保留Ext3格式,但新的文件将采用新的Ext4数据结构。
2) 提高时间戳分辨率和扩展范围
Ext4之前的扩展文件系统的时间戳都是以秒为单位的,这足以应付大多数设置,但随着处理器的速度和集成程度(多核处理器)不断提升,以及Linux开始向其他应用领域发展(比如高性能计算),基于秒的时间戳已经不够用。Ext4在设计时间戳时考虑到未来的发展,它将时间戳的单位提升到纳秒。Ext4给时间范围增加了两个位,从而让时间长度再延长500年。
问个问题:处理器的速度和文件的时间属性啥关系?秒的时间戳为啥不够用?
3) 突破文件系统的限制
Ext4的一个明显差别是支持更大的文件系统、文件和子目录。Ext4支持的最大文件系统为1EB(1000 PB)。虽然根据今天的标准这个文件系统已经非常巨大,但存储空间的消费会不断增长,因此Ext4必须考虑到未来的发展。Ext4支持最大16TB的文件(假设由4KB的块组成),这个容量是Ext3的8倍。最后,Ext4也扩展了子目录的容量,将其从 32KB扩展到无穷大。这是极端情况,还需要考虑文件系统的层次结构,因为它的最大存储容量为1EB。此外它的目录索引被优化为类似于散列 B 树结构,因此尽管限制更加多,但Ext4支持更快的查找。
4) 分配空间的方式:区段和区段树
分配空间的方式是Ext3主要缺点之一。Ext3 使用空闲空间位映射来分配文件,这种方式不是很快,并且伸缩性不强。Ext3的格式对小文件而言是很高效的,但对于大文件则恰恰相反。Ext4使用区段取代Ext3的机制,从而改善了空间的分配,并且支持更加高效的存储结构。区段是一种表示一组相邻块的方式。使用区段减少了元数据,因为区段维护关于一组相邻块的存储位置的信息(从而减少总体元数据存储),而不是一个块的存储位置的信息。Ext4的区段采用分层的方法高效地表示小文件,并且使用区段树高效地表示大文件。例如,单个Ext4 inode有足够的空间来引用4 个区段。对于大文件,一个inode能够引用一个索引节点,而每个索引节点能够引用一个叶节点。这种持续的区段树为大文件提供了丰富的表示方式。这些索引节点还包含自主检查机制,以阻止文件系统损坏带来威胁。
5) 文件级预分配
某些应用程序,比如数据库或内容流,要求将文件存储在相邻的块上。尽管区段能够将相邻块划分为片段,但另一种更强大的方法是按照所需的大小预分配比较大的相邻块。Ext4实现一个新的系统调用:将按照特定的大小预分配并初始化文件。然后写入必要的数据,并为数据提供不错的读性能。
6) 延迟物理块的分配
延迟磁盘上的物理块的分配,直到块被刷入到磁盘时才分配并写到相邻的块。类似于持久化预分配,唯一的区别是文件系统会自动执行这个任务。如果预先知道文件的大小,则持久化预分配是更好的选择。
7) Ext4块分配器支持多个块分配
Ext3的块分配器的工作方式是每次分配一个块。当需要分配多个块时,非相邻块中可能存在相邻的数据。Ext4的块分配器解决了这个问题,它能够在磁盘上一次分配多个块。支持多个块分配意味着分配块时的处理量。Ext3每个块的分配都要有一个调用。如果一次分配多个块,则对块分配器的调用就会大大减少,从而加快分配并减少处理量。
8) 可靠性
Ext4文件系统可能会被扩展得比较大,这将导致可靠性问题。但Ext4通过许多自主保护和自主修复机制来解决这个问题。
9) 执行文件系统日志校验和
和Ext3一样,Ext4也是通过日记(磁盘上相邻区域的专门循环记录)记录文件系统变更的过程。即使在操作期间出现系统崩溃或电源中断,对物理存储执行变更更可靠,并能确保一致性,可以减少文件系统损坏的几率。但日志记录也会出现错误仍然会导致文件系统损坏。为了解决这个问题,Ext4对日志执行校验和,确保有效变更能够在底层文件系统上正确完成。
Ext4和ext3一样支持采用多种模式的日志记录:Writeback、Ordered、Journal。
10) 在线磁盘碎片整理:e4defrag
尽管Ext4增加了一些特性来减少文件系统的碎片(比如将相邻块分配为区段),但随着系统使用时间的增加,碎片是难以完全避免的。在线碎片整理工具e4defrag可以对文件系统和单个文件执行碎片整理,从而改善性能。在线碎片整理工具将文件复制到引用相邻区段的新Ext4 inode。在线碎片整理可以减少检查文件系统所需的时间(fsck)。Ext4将未使用的块组标记到 inode表中,并让fsck进程忽略它们以加快检查速度。当操作系统因内部损坏而检查文件系统时,Ext4的设计方式能提高总体的可靠性。
高性能日志文件系统XFS ( eXtended File System)
XFS的并行I/O特性为I/O线程、文件系统带宽、文件和文件系统大小提供了高可扩展性,甚至在文件系统跨越很多存储设备的时候,典型使用案例是跨越多个存储服务器,每个服务器由很多FC连接的磁盘阵列组成,实现几百TB的文件系统。
XFS拥有大量的功能,其适合部署企业级计算环境,它们都需要实现非常巨大的文件系统:
在x86_64系统上,XFS支持的最大文件系统和最大文件近8EB。而Redhat仅支持100TB文件系统。
XFS实现了元数据的日志操作,能在掉电或系统崩溃的情况下保证文件系统的一致性。在提交实际的数据更新到磁盘之前,XFS将文件系统更新异步记录到一个循环缓冲区(日志)。日志可以位于文件系统内部的数据段,或是外部一个单独的设备上,这样可以减少磁盘访问的竞争。如果系统崩溃或掉电,当文件系统重新挂载时会读取日志,重新执行任何挂起的元数据操作,以确保文件系统的一致性。恢复的速度不依赖于文件系统的大小。
XFS内部划分的分配组,它们是固定大小的虚拟存储区域。创建的任何文件和目录可以跨越多个分配组。每个分配组管理自己拥有的inode和可用空间,独立于其他分配组,这提供了I/O操作的扩展性和并行性。如果文件系统跨多个物理设备,则分配组可以通过将底层信道分离到存储组件来优化吞吐量。
XFS是一个基于范围的文件系统。可以减少文件的分片和文件的分散程度,每个文件的块可以有可变的范围长度,每个范围可以由一个或多个连续的块组成。XFS采用空间分配方案的目的是有效地找到空闲的范围,它可以用于文件系统操作。如果可能的话,文件范围分配的映射存储在该文件的inode中。巨大的分配映射被存储在由分配组进行维护的数据结构中。
为了最大化吞吐量,可以在底层条带化的基于软件或硬件阵列上创建XFS文件系统,可以使用su和sw参数给mkfs.xfs的-d 选项设置每个条带单元的大小和每个条带单元的数量,XFS使用这些信息存储适当的调整数据、inode和日志。在LVM、md和一些硬件RAID上配置,XFS可以自动选择最佳的条带参数。
为了减少分片和提高性能,XFS实现了延迟分配,对缓冲区缓存中的数据保留文件系统块,而当操作系统刷新数据到磁盘的时候再分配块。
XFS支持扩展的文件属性,每个属性值的大小可以高达64KB,并且每个属性可以被分配给任意root或普通用户名称空间。
在XFS中,直接I/O实现了高吞吐量。在应用程序和存储设备之间通过DMA可直接执行非缓存I/O,从而利用设备的全部I/O带宽。
要支持提供的快照设备,如卷管理器、硬件子系统、数据库,可以使用xfs_freeze命令挂起和恢复一个XFS文件系统的I/O。
要在活跃的XFS文件系统中进行单个文件的碎片整理,可以使用 xfs_fsr命令。要增长XFS文件系统,可以使用xfs_growfs命令。要备份和恢复一个活跃的XFS文件系统,可以使用 xfsdump和xfsrestore命令。
当文件系统被挂载时初始化块和inode的使用,XFS支持用户、组和项目的磁盘配额。项目磁盘配额允许设置XFS文件系统中单独目录层级结构的限制,而不用考虑哪些用户或组写访问到目录层级结构。
XFS 的局限性
XFS是一个单节点文件系统,如果需要多节点同时访问则需要考虑使用GFS2文件系统。
XFS支持16EB文件系统,而RedHat仅支持100TB文件系统。
XFS在单线程元数据密集的工作负荷下使用得较少,在单线程创建和删除巨大数量的小文件的工作负荷下,其他文件系统(Ext4)表现得会更好一些。
XFS文件系统在操作元数据时可能会使用2倍的Ext4CPU资源,在CPU资源有限的情况下可以研究使用不同的文件系统。
XFS更适用于特大文件的系统快速存储,Ext4在小文件的系统或系统存储带宽有限的情况下表现得更好。
参考
读书笔记来自赵永刚老师的《Linux性能优化大师》,如有侵权,请通知删除。