CXD Linux Engineer

Linux中的ETX4文件系统介绍

2017-06-20

前言

本篇文章是翻译于:The File system,翻译了一半发现网上已经有人已经把这篇文章翻译完了,所以剩下的一半就没有动力翻译下去了。。。直接使用了被人的翻译。注,本文章后半段转载于这篇文章:Linux 的 EXT4 文件系统的历史、特性以及最佳实践

本文从EXT4文件系统的历史、特性、最佳使用方式等方面进行讨论并会介绍EXT4与以前的老版本EXT文件系统之间的区别。

在关于Linux文件系统的文章中我以前写过一篇an introduction to Linux filesystems,和一些介绍Linux文件系统中的一些高层次概念的文章,例如:everything is a file。这篇文章我想更加深入的分析EXT文件系统的具体实现细节,但是我们首先得解答一个问题“什么是文件系统?”下面是一个文件系统所具有的基本元素:

  1. 数据存储:文件系统的最主要作用是有组织的保存和检索数据
  2. 命名空间:提供一种命名和组织方法来标记和结构化存储数据
  3. 安全模式:定义一种控制访问权限的规则
  4. API:提供用于维护文件系统对象例如目录和文件的系统调用
  5. 实现:实现上面所有功能的软件

本文主要介绍列表中的第一条,探讨EXT文件系统中的元数据结构和存储数据的组织框架。

EXT文件系统的历史

虽然本文是介绍Linux中的EXT文件系统,但是EXT文件系统最早起源于Minix操作系统和Minix文件系统,它首次在1987年发布比Linux早5年。现在讨论EXT4还为时尚早,我们需要从EXT文件系统的根源Minix开始介绍它的历史和技术演化历程。

Minix

Linus在开发初始版Linux内核时需要一个文件系统但是又不想重复造轮子,因此他只是简单的将Minix的文件系统移植进来了,Minix文件系统本来是Andrew S. TanenbaumTanenbaum的Minix操作系统开发的。Minix是一个用于教学目的的类Unix操作系统,Minix的代码可以免费获取并且它的许可证允许Torvalds将它包含到Linux的第一个版本中。

Minix具有以下结构,其中大多数位于生成文件系统的分区中:

  • 位于硬盘中第一个扇区的引导扇区。这个引导扇区包含了一个非常小的引导记录和分区表。
  • 每个分区中的第一个块是超级块,它保存了文件系统中的其他数据结构和这些数据结构在该分区中的位置。
  • 一个节点位图数据块,它记录了哪些节点被使用了,哪些节点是空闲的。
  • inode他们在磁盘中有自己的空间。每个inode保存着一个文件的信息,这些信息包括数据块的位置即哪些数据块属于这个文件。
  • 区位图用于记录哪些数据块被使用,哪些数据块是空闲的。
  • 数据块用于存储实际数据

不同类型的位图中的一个bit代表一个具体的数据块或者inode,如果这个bit是0表示这个数据块或者inode是空闲的可以被使用。当这个bit是1则表示这个数据块或者inode已经被使用。

inode是个什么东西?他是index-node的缩写,一个inode是一个256字节的块,他保存着文件的信息。这些信息包括文件的大小、文件所属用户的ID、文件的权限和文件的三个时间戳,分别代表:文件的最后访问时间、文件的最后修改时间和此inode的最后修改时间。

inode中也保存着该文件的数据在磁盘中的位置信息。在Minix和EXT1-3文件系统中这些位置信息就是一个数据块列表。Minix文件系统的inode列表最大支持9个数据块,其中7个直接块和2个间接块。如果你想了解更多,这有一个非常好的PDF文档介绍Minix文件系统的实现细节Minix filesystem structure,也可以在Wikipedia上查看inode pointer structure这篇文章快速讲解了inode基本结构。

EXT

EXT文件系统最初是Rémy Card开发出来的,于1992年和Linux一起发布目的是为了克服Minix文件系统对单个文件最大体积的限制。主要的变化是文件系统的元数据结构的改变,它基于Unix的文件系统UFS,也被成为Berkeley Fast File SystemFFS文件系统。现在已经很难找到EXT文件系统的相关信息,因为它有一个很大的Bug,所以很快就被EXT2文件系统所代替。

EXT2

EXT2是一个非常成功的文件系统,它在Linux的发行版中使用了很多年,并且这是我接触的第一个文件系统,1997年在我开始使用Red Hat Linux 5.0系统上。EXT2文件系统的元数据结构和EXT文件系统实际上是一样的,但是EXT2更具有前瞻性,它在元数据附近预留了很多磁盘空间供未来使用。

和Minix一样,EXT2也有一个启动扇区位于磁盘的第一个扇区,它保存着一个很小的引导记录和一个分区表。启动扇区后面保留了一部分空间,GRUB2或GRUB1会利用这部分空间存储启动代码。

EXT2将每个分区又细分为柱面组以便于更精细的管理。在我的经验中每个组的大小是8MB。图1 展示了一个柱面组的基本结构,数据是以块为单位存贮的,每个块的大小通常是4KB。

1

柱面组的第一块是一个超级块,它保存着其他数据结构的定义和位置信息。分区中的其他组也会有这个超级块的备份,但不是所有的组都有。如果超级块损坏,可以使用磁盘工具例如dd来拷贝一个备份超级块到主超级块中。这种事情不会经常发生,但是一旦发生备份的超级块就可以用来恢复数据了。

下面是使用dumpe2fs工具输出的信息,它展示了超级块中的原始数据和文件系统中前两个柱面组中的数据:

# dumpe2fs /dev/sda1
Filesystem volume name:   boot 
Last mounted on:          /boot 
Filesystem UUID:          79fc5ed8-5bbc-4dfe-8359-b7b36be6eed3 
Filesystem magic number:  0xEF53 
Filesystem revision #:    1 (dynamic) 
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file dir nlink extra_isize 
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl 
Filesystem state:         clean 
Errors behavior:          Continue 
Filesystem OS type:       Linux 
Inode count:              122160 
Block count:              488192 
Reserved block count:     24409 
Free blocks:              376512 
Free inodes:              121690 
First block:              0 
Block size:               4096 
Fragment size:            4096 
Group descriptor size:    64 
Reserved GDT blocks:      238 
Blocks per group:         32768 
Fragments per group:      32768 
Inodes per group:         8144 
Inode blocks per group:   509 
Flex block group size:    16 
Filesystem created:       Tue Feb  7 09:33:34 2017 
Last mount time:          Sat Apr 29 21:42:01 2017 
Last write time:          Sat Apr 29 21:42:01 2017 
Mount count:              25 
Maximum mount count:      -1 
Last checked:             Tue Feb  7 09:33:34 2017 
Check interval:           0 (<none>) 
Lifetime writes:          594 MB 
Reserved blocks uid:      0 (user root) 
Reserved blocks gid:      0 (group root) 
First inode:              11 
Inode size:               256 
Required extra isize:     32 
Desired extra isize:      32 
Journal inode:            8 
Default directory hash:   half_md4 
Directory Hash Seed:      c780bac9-d4bf-4f35-b695-0fe35e8d2d60 
Journal backup:           inode blocks 
Journal features:         journal_64bit 
Journal size:             32M 
Journal length:           8192 
Journal sequence:         0x00000213 
Journal start:            0 


Group 0: (Blocks 0-32767) 
 Primary superblock at 0, Group descriptors at 1-1 
 Reserved GDT blocks at 2-239 
 Block bitmap at 240 (+240) 
 Inode bitmap at 255 (+255) 
 Inode table at 270-778 (+270) 
 24839 free blocks, 7676 free inodes, 16 directories 
 Free blocks: 7929-32767 
 Free inodes: 440, 470-8144 
Group 1: (Blocks 32768-65535) 
 Backup superblock at 32768, Group descriptors at 32769-32769 
 Reserved GDT blocks at 32770-33007 
 Block bitmap at 241 (bg #0 + 241) 
 Inode bitmap at 256 (bg #0 + 256)
 Inode table at 779-1287 (bg #0 + 779) 
 8668 free blocks, 8142 free inodes, 2 directories 
 Free blocks: 33008-33283, 33332-33791, 33974-33975, 34023-34092, 34094-34104, 34526-34687, 34706-34723, 34817-35374, 35421-35844, 35935-36355, 36357-36863, 38912-39935, 39940-40570, 42620-42623, 42655, 42674-42687, 42721-42751, 42798-42815, 42847, 42875-42879, 42918-42943, 42975, 43000-43007, 43519, 43559-44031, 44042-44543, 44545-45055, 45116-45567, 45601-45631, 45658-45663, 45689-45695, 45736-45759, 45802-45823, 45857-45887, 45919, 45950-45951, 45972-45983, 46014-46015, 46057-46079, 46112-46591, 46921-47103, 49152-49395, 50027-50355, 52237-52255, 52285-52287, 52323-52351, 52383, 52450-52479, 52518-52543, 52584-52607, 52652-52671, 52734-52735, 52743-53247 
 Free inodes: 8147-16288 
Group 2: (Blocks 65536-98303) 
 Block bitmap at 242 (bg #0 + 242) 
 Inode bitmap at 257 (bg #0 + 257) 
 Inode table at 1288-1796 (bg #0 + 1288) 
 6326 free blocks, 8144 free inodes, 0 directories 
 Free blocks: 67042-67583, 72201-72994, 80185-80349, 81191-81919, 90112-94207 
 Free inodes: 16289-24432 
Group 3: (Blocks 98304-131071)

<snip>

每个柱面组中都有自己的inode位图,用于标记这个组中被使用和未被使用的inode。这些inode都有他们自己的空间,每个inode保存着每个文件的相关信息,其中就有文件数据的存放位置信息。块位图用于标记文件系统中已经使用和空闲的数据块。注意,在上面的输出中有大量关于文件系统的数据。在非常大的文件系统上,柱面组中的数据可以长达数百页。柱面组的元数据包括组中所有空闲数据块的列表。译者注:下面的是由别人翻译的。

EXT文件系统实现了数据分配策略以确保产生最少的文件碎片。减少文件碎片可以提高文件系统的性能。这些策略会在下面的EXT4中描述到。

我所遇见的关于EXT2文件系统最大的问题是fsck(文件系统检查) 程序这一环节占用了很长一段时间来定位和校准文件系统中的所有的不一致性,从而导致在系统崩溃crash后其会花费了数个小时来修复。有一次我的其中一台电脑在崩溃后重新启动时共花费了28个小时恢复磁盘,而且并且是在磁盘被检测量只有几百兆字节大小的情况下。

EXT3

EXT3文件系统是应一个目标而生的,就是克服fsck程序需要完全恢复在文件更新操作期间发生的不正确关机而损坏的磁盘结构所需的大量时间。它对EXT文件系统的唯一新增功能就是日志,它将提前记录将对文件系统执行的更改。EXT3的磁盘结构的其余部分与EXT2中的相同。

除了同先前的版本一样直接写入数据到磁盘的数据区域外,EXT3上的日志会将文件数据随同元数据写入到磁盘上的一个指定数据区域。一旦这些(日志)数据安全地到达硬盘,它就可以几乎零丢失率地被合并或被追加到目标文件上。当这些数据被提交到磁盘上的数据区域上,这些日志就会随即更新,这样在日志中的所有数据提交之前,系统发生故障时文件系统将保持一致状态。在下次启动时,将检查文件系统的不一致性,然后将仍保留在日志中的数据提交到磁盘的数据区,以完成对目标文件的更新。

日志功能确实降低了数据写入性能,但是有三个可用于日志的选项,允许用户在性能和数据完整性、安全性之间进行选择。我的个人更偏向于选择安全性,因为我的环境不需要大量的磁盘写入活动。

日志功能将失败后检查硬盘驱动器所需的时间从几小时(甚至几天)减少到了几分钟。多年来,我遇到了很多导致我的系统崩溃的问题。要详细说的话恐怕还得再写一篇文章,但这里需要说明的是大多数是我自己造成的,就比如不小心踢掉电源插头。幸运的是,EXT日志文件系统将启动恢复时间缩短到两三分钟。此外,自从我开始使用带日志记录的EXT3,我从来没有遇到丢失数据的问题。

EXT3的日志功能可以关闭,然后其功能就等同于EXT2文件系统了。该日志本身仍然是存在的,只是状态为空且未使用。只需在mount命令中使用文件系统类型参数来重新挂载即可指定为EXT2。你可以从命令行执行此操作,但是具体还是取决于你正在使用的文件系统,不过你也可以更改/etc/fstab文件中的类型说明符,然后重新启动。我强烈建议不要将EXT3文件系统挂载为EXT2,因为这会有丢失数据和增加恢复时间的潜在可能性。

EXT2文件系统可以使用如下命令来通过日志升级到EXT3。

tune2fs -j /dev/sda1

/dev/sda1表示驱动器和分区的标识符。同时要注意修改/etc/fstab中的文件系统类型标识符并重新挂载分区,或者重启系统以确保修改生效。

EXT4

EXT4文件系统主要提高了性能、可靠性和容量。为了提高可靠性,它新增了元数据和日志校验和。同时为了满足各种关键任务要求,文件系统新增了纳秒级别的时间戳,并在时间戳字段中添加了两个高位来延缓时间戳的2038年问题,这样EXT4文件系统至少可用到2446年。

在EXT4中,数据分配从固定块改为扩展盘区extent方式,扩展盘区由硬盘驱动器上的开始和结束位置来描述。这使得可以在单个inode指针条目中描述非常长的物理上连续的文件,这可以显著减少描述大文件中所有数据的位置所需的指针数。其它在EXT4中已经实施的分配策略可以进一步减少碎片化。

EXT4通过将新创建的文件散布在磁盘上,使其不会像早期的PC文件系统一样全部聚集在磁盘起始位置,从而减少了碎片。文件分配算法尝试在柱面组中尽可能均匀地散布文件,并且当文件(由于太大)需要分段存储时,使不连续的文件扩展盘区尽可能靠近同一文件中的其他部分,以尽可能减少磁头寻道和电机旋转等待时间。当创建新文件或扩展现有文件时,使用其它策略来预先分配额外的磁盘空间。这有助于确保扩展文件时不会自动导致其分段。新文件不会紧挨这现有文件立即分配空间,这也可以防止现有文件的碎片化。

除了磁盘上数据的实际位置外,EXT4使用诸如延迟分配的功能策略,以允许文件系统在分配空间之前收集到所有正在写入磁盘的数据,这可以提高数据空间连续的可能性。

较旧的EXT文件系统(如EXT2和EXT3)可以作为EXT4进行mount,以使其性能获得较小的提升。但不幸的是,这需要关闭EXT4的一些重要的新功能,所以我建议不要这样做。

自Fedora14以来,EXT4一直是Fedora的默认文件系统。我们可以使用Fedora文档中描述的流程将EXT3文件系统升级到EXT4,但是由于仍然存留的之前的EXT3元数据结构,它的性能仍将受到影响。从EXT3升级到EXT4的最佳方法是备份目标文件系统分区上的所有数据,使用mkfs命令将空EXT4文件系统写入分区,然后从备份中恢复所有数据。

inode

之前介绍过的inode是EXT文件系统中的元数据的关键组件。图2显示了inode和存储在硬盘驱动器上的数据之间的关系。该图是单个文件的目录和inode,在这种情况下,可能会产生高度碎片化。EXT文件系统可以主动地减少碎片,所以不太可能会看到有这么多间接数据块或扩展盘区的文件。实际上,你在下面将会看到,EXT文件系统中的碎片非常低,所以大多数inode只使用一个或两个直接数据指针,而不使用间接指针。

2
图2:inode存储有关每个文件的信息,并使EXT文件系统能够查找属于它的所有数据。

inode不包含文件的名称。通过目录项访问文件,目录项本身就是文件的名称,并包含指向inode的指针。该指针的值是inode号。文件系统中的每个inode都具有唯一的ID号,但同一台计算机上的其它文件系统(甚至是相同的硬盘驱动器)中的inode可以具有相同的inode号。这对硬链接存在影响,但是这个讨论超出了本文的范围。

inode包含有关该文件的元数据,包括其类型和权限以及其大小。inode还包含15个指针的空位,用于描述柱面组数据部分中数据块或扩展盘区的位置和长度。12个指针提供对数据扩展盘区的直接访问,应该足以满足大多数文件的需求。然而,对于具有明显分段的文件,需要以间接节点node的形式提供一些额外的容量——从技术上讲,这些不是真正的“inode”,所以为了方便起见我在这里使用这个术语“节点node”。

间接节点是文件系统中的正常数据块,它仅用于描述数据而不用于存储元数据,因此可以支持超过15个条目。例如,4K的块大小可以支持512个4字节的间接节点,允许单个文件有12(直接)+512(间接)=524个扩展盘区。还支持双重和三重间接节点,但我们大多数人不太可能遇到需要那么多扩展盘区的文件。

数据碎片

对于许多较旧的PC文件系统,如FAT(及其所有变体)和NTFS,碎片一直是导致磁盘性能下降的重大问题。碎片整理本身就成为一个行业,有各种品牌的整理软件,其效果范围从非常有效到仅仅是微乎其微。

Linux的扩展文件系统使用数据分配策略,有助于最小化硬盘驱动器上的文件碎片,并在发生碎片时减少碎片的影响。你可以使用EXT文件系统上的fsck命令检查整个文件系统的碎片。以下示例检查我的主工作站的家目录,只有1.5%的碎片。确保使用-n参数,因为它会防止fsck对扫描的文件系统采取任何操作。

fsck -fn /dev/mapper/vg_01-home

我曾经进行过一些理论计算,以确定磁盘碎片整理是否会产生任何明显的性能提升。 我做了一些假设条件,我使用的磁盘性能数据来自一个新的 300GB 的西部数字硬盘驱动器,具有 2.0ms 的轨到轨寻道时间。 此示例中的文件数是我在计算的当天的文件系统中存在的实际数。 我假设每天有相当大量的碎片化文件(约 20%)会被用到。

3

我对每天的全部的额外寻道时间进行了两次计算,一次是轨到轨寻道时间,这是由于EXT文件分配策略而导致大多数文件最可能的情况,一个是平均寻道时间,我假设这是一个合理的最坏情况。

从表1可以看出,对绝大多数应用程序而言,碎片化甚至对性能适中的硬盘驱动器上的现代EXT文件系统的影响是微乎其微的。您可以将您的环境中的数字插入到您自己的类似电子表格中,以了解你对性能影响的期望。这种类型的计算不一定能够代表实际的性能,但它可以提供一些对碎片化及其对系统的理论影响的洞察。

我的大部分分区的碎片率都在1.5%左右或1.6%,我有一个分区有3.3%的碎片,但是这是一个大约128GB文件系统,具有不到100个非常大的ISO映像文件;多年来,我扩展过该分区几次,因为它已经太满了。

这并不是说一些应用的环境并不需要更少的碎片的环境。EXT文件系统可以由有经验和知识的管理员小心调整,管理员可以针对特定的工作负载类型调整参数。这个工作可以在文件系统创建的时候或稍后使用tune2fs命令时完成。每一次调整变化的结果应进行测试,精心的记录和分析,以确保目标环境的最佳性能。在最坏的情况下,如果性能不能提高到期望的水平,则其他文件系统类型可能更适合特定的工作负载。并记住,在单个主机系统上混用文件系统类型以匹配每个文件系统上的不同负载是常见的。

由于大多数EXT文件系统的碎片数量较少,因此无需进行碎片整理。目前,EXT文件系统没有安全的碎片整理工具。有几个工具允许你检查单个文件的碎片程度或文件系统中剩余可用空间的碎片程度。有一个工具,e4defrag,它可以对允许使用的剩余可用空间、目录或文件系统进行碎片整理。顾名思义,它只适用于EXT4文件系统中的文件,并且它还有一其它的些限制。

如果有必要在EXT文件系统上执行完整的碎片整理,则只有一种方法能够可靠地工作。你必须将文件系统中的所有要进行碎片整理的文件移动从而进行碎片整理,并在确保安全复制到其他位置后将其删除。如果可能,你可以增加文件系统的大小,以帮助减少将来的碎片。然后将文件复制回目标文件系统。但是其实即使这样也不能保证所有文件都被完全去碎片化。

总结

EXT文件系统在一些Linux发行版本上作为默认文件系统已经超过二十多年了。它们用最少的维护代价提供了稳定性、高可用性、可靠性和性能。我尝试过一些其它的文件系统但最终都还是回归到EXT。每一个我在工作中使用到Linux的地方都使用到了EXT文件系统,同时我发现了它们适用于任何主流负载。毫无疑问,EXT4文件系统应该被用于大部分的Linux文件系统上,除非我们有明显需要使用其它文件系统的理由。


Comments

Content