【转发】ext4文件系统

原文路径

ext4文件系统

linux的拓展文件系统,从第一代ext为人们所熟知,经过ext2、ext3、ext4发展,逐步成为linux上首选的文件系统,目前比较常用的是ext3和ext4,ext3的用户也将慢慢升级到ext4。本文介绍这两个文件系统的区别,ext4在ext3的基础上做了哪些改进,中间穿插一些文件系统基础知识,希望通过本文大家能对ext4有大致的了解。

磁盘布局

在了解文件系统前,先简单了解下磁盘是怎样布局的。磁盘都会进行逻辑空间划分,分为一个个分区,有GPT和MBR划分机制,本文介绍MBR机制,磁盘被分成最多4个分区;下图一个磁盘被分为3个主分区和一个拓展分区,每个分区包含boot block部分;拓展分区拓展了区域,称为逻辑分区;MBR部分是整个系统的开始部分,包括引导程序boot code和分区表信息。

【转发】ext4文件系统_第1张图片

MBR引导程序通过分区表找到一个活动的分区表,将活动分区的启动程序从设备加载到RAM并且执行,该程序负责进一步的操作系统的加载和启动。

一个文件系统使用一个独立的分区,不同的分区可以使用不同的文件系统,linux只有一个根目录「/」,其他分区是需要挂在根目录下面某个目录才能使用。

磁盘在物理上将一段范围磁柱划分为数据块,一个块究竟多大是在格式化时确定的,例如mke2fs的-b选项可以设定块大小为1024、2048或4096字节,默认为4KB。

ext3 布局

磁盘分区好之后,就能在分区上创建文件系统了。一个分区格式化成ext3文件系统,磁盘的布局如下图:

【转发】ext4文件系统_第2张图片

文件系统最前面有一个启动扇区(boot block),这个启动块可以安装启动管理程序,这是个非常重要的设计,因为如此一来我们就能够将不同的启动管理程序安装到个别的文件系统最前端,而不用覆盖唯一的 MBR。

  • Super Block: 大小为1k,Superblock 是记录整个 filesystem 相关信息的地方,超级块位于每个块组的最前面,每个块组包含超级块的内容是相同的(超级块在每个块组的开头都有一份拷贝);下图是super block的内容

【转发】ext4文件系统_第3张图片

  • GDT:块组描述符表,由很多块组描述符组成,Linux组描述符为32字节,整个分区分成多少个块组就对应有多少个块组描述符;和超级块类似,块组描述符表在每个块组的开头也都有一份拷贝,具有相同内容的组描述符表放在每个块组中做为备份,这些信息是非常重要的。

  • Block Bitmap:块位图,用来描述本块组中数据块的使用状况,它本身占一个数据块。

  • Inode Bitmap:inode位图,和块位图类似,本身占一个块,其中每个bit表示一个inode是否空闲可用。
  • Inode Table:inode表,存储本块组的inode序号和inode保存的位置。
  • Data block: 存放数据的地方;

ext4磁盘布局

ext4基本磁盘布局跟ext3的基本差不多,都是以块组管理,但有增加了一些特性。

  1. Flexible 块组
    如果开启flex_bg特性,在一个flex_bg中,几个块组在一起组成一个逻辑块组flex_bg。flex_bg的第一个块组中的位图空间和inode表空间扩大为包含了flex_bg中其他块组上位图和inode表。如下图flex_bg包含4个块组,块组0将按序包含超级块、块组描述符表、块组0-3的数据块位图、块组0-3的inode位图、块组0-3的inode表,块组0中的其他空间用于存储文件数据。同时,其他块组上的数据块位图、inode位图、inode表元数据就不存在了,但是Super Block和GDT还是存在的。

    【转发】ext4文件系统_第4张图片

    Flexible块组的作用是:
    (1) 聚集元数据,加速元数据载入;
    (2) 使得大文件在磁盘上尽量连续;
    最终目的都是减少磁盘寻道时间;

  2. 元块组 Meta Block Groups
    以ext4为例,一个Block Group的大小为默认大小为127MB,Ext4的块组描述符大小64 Bytes计算,文件系统中最多只能有2^21个块组,也就是文件系统最大为256TB。
    如果打开META_BG的选项,ext4文件系统将被分成多个metablock groups。每个metablock group是block groups的集合。对于block size 为4KB的ext4文件系统,一个metablock group包含64个block group = 8GB,GDT将存储在medablock group中的第一个block group中,并且在medablock group中第二和最后一个作备份。这种方式即可以实现消除中256T的限制,即2^32 *2^27=512PB。

inode

一个文件除了自身的数据之外,还有一个附属信息,即文件的元数据(metadata)。这个元数据用于记录文件的许多信息,比如文件大小,拥有人,所属的组,修改日期等等。元数据并不包含在文件的数据中,而是由文件系统维护的,这些数据就保存在inode中,当然inode内容也保存在data block中。我们可以用 ls -l filename 来查看这些元数据。

inode保存的主要信息:

  • 该文件的存取模式(read/write/excute);
  • 该文件的拥有者与群组(owner/group);
  • 该文件的容量;
  • 该文件创建或状态改变的时间(ctime);
  • 最近一次的读取时间(atime);
  • 最近修改的时间(mtime);
  • 定义文件特性的旗标(flag),如 SetUID…;
  • 该文件保存数据块的指针 (pointer);

inode节点大小是128字节,每个文件都必须占用一个inode,因此文件系统能够创建的文件数量与 inode 的数量有关, inode表占多少个块在格式化时就要决定并写入块组描述符中,mke2fs格式化工具的默认策略是一个块组有多少个8KB就分配多少个inode。

inode保存了数据的存放block的指针,是怎么工作的呢,ext3和ext4又有所不同。

ext3文件寻址

【转发】ext4文件系统_第5张图片

如上图所示,ext3包含了15个指针,12个直接指针,一个间接指针,一个二次间接指针,一个三次间接指针。

这样子一个inode能够存多大的文件呢?我们以 4KB block 来说明好了,可以指定的情况如下:

  • 12个直接指向: 12*4K=48K;

  • 间接: 1K * 4K = 4M;一个指针占4bytes,因此4KB的大小block能够存1K个指针,因此一个间接可以记录的文件大小为4M;

  • 二次间接指针: 1K 1K 4K=4G
    第一层 block 会指定 1K 个第二层,每个第二层可以指定 1K 个block;

  • 三次间接指针: 1K 1K 1K * 4K = 4T;

ext4文件寻址

Ext3 采用间接索引映射,当操作大文件时,效率极其低下。比如一个 100MB 大小的文件,在 Ext3中要建立 25,600 个数据块(每个数据块大小为 4KB)的映射表。而 Ext4 引入了现代文件系统中流行的区段 extents 概念,每个 extent 为一组连续的数据块,上述文件则表示为“该文件数据保存在接下来的 25,600 个数据块中”,提高了不少效率。

【转发】ext4文件系统_第6张图片

如上图,区段extents根据内容分为索引节点 extent_idx ,内容叶子节点extent。extent内容包含了起始的block地址和length,length占16个字节,因此对于4KB的block,每个extent能定位128M连续的寻址空间。 inode默认有4个extent,每个extent可以直接指向一段连续的block;如果这4个extent不能满足文件大小,则extent变成extent_idx索引节点 , 像ext3间接索引一样,一级级拓展,形成一个BTree。

使用区段分配数据块好处显而易见,减少了映射表项,还分配连续的空间,减少磁头的移动,增加效率,同时没有文件大小的限制。

目录索引

前面我们说过,创建一个文件需要占用一个inode节点,和至少一个block。inode存元数据,block存文件内容,如果是目录呢?
目录也是一个文件,也需要分配一个inode节点,和至少一个block。不过block里面存储的是在这个目录下的文件名与该文件的inode编号。下面是 / 目录的数据块存储的entry项。

inode编号 文件名
2 .
2 ..
655362 home
786433 var

当我们读取一个文件时/home/aa.txt,先找到 / 的inode,然后读入inode指向的数据块,找到 home entry, 从entry中获得并读入inode,再读入home的block,检索的aa.txt entry的inode编号,最后根据编号,读取aa.txt的文件内容。

像ext2要检索目录下某个entry,就得顺序读入该目录指向的block,直到读到为止。线性检索时间复杂度为O(n),在一个目录超过10000文件时,性能就会有影响。

在ext3中,增加了dir_index特性,为一个目录下面的表项创建索引,提高目录和文件的检索速度,ext3中需要手动开启这个特性,ext4中默认开启这个特性。

dir_index特性中,将目录下的文件名进行hash计算,以Hash Tree的组织保存在block中。

【转发】ext4文件系统_第7张图片

上图中一个目录下面的所有entry被组织成一颗平衡的hash tree。
树的根就是存储在目录的第一个数据块,即dx_root,其中叶节点存储的目录项的内容,当前目录项并非按照线性排序了,而是hash值处于某一个范围内的目录项存储在一个目录项块中;中间节点存储的是存储的是索引项,内容和第一个目录数据块块内容基本一致。

当前每个索引项dx_entry占8个字节,索引树根部dx_root占32个字节,对于一个4KB大小的块,即如图的第一层索引,可以索引508个叶块或节点块,第二层索引可以索引511个块,那么目录索引树支持目录大小为508×511×4KB=1014MB,假定一个目录下文件名平均由22个字符长度,那么一个目录项即30B,那么二级索引树最大支持约34M个文件,即3400万个文件,满足了绝大部分的存储场景需求。

ext3和ext4中都只支持二层索引,所以要查找一个目录entry,只需要读取3个数据块,速度快了很多。

ext4更多特性

  • 向后和向前兼容性:可以将 ext3 文件系统挂载为 ext4 文件系统;可以将 ext4 挂载为 ext3(向后兼容),但前提是ext4 文件系统不能使用区段特性;

  • 提高时间戳分辨率: ext4的时间戳精确到纳秒,而之前都是以秒来记录;

  • 突破文件系统的限制: 从上面的分析可以看到,ext4它支持更大的文件系统、文件和子目录;

  • 区段分配:ext3 使用空闲空间位映射来分配文件,这种方式不是很快,并且伸缩性不强。ext3 的格式对小文件而言是很高效的,但对于大文件则恰恰相反。ext4 使用区段取代 ext3 的机制,从而改善了空间的分配,并且支持更加高效的存储结构。ext4从分配上进行很多优化,尽量使文件聚集在相邻的块上。

    • 文件级预分配:
      某些应用程序,比如数据库或内容流,要求将文件存储在相邻的块上(利用相邻块的读优化和最大化读的命令-块比率)。尽管区段能够将相邻块划分为片段,但另一种更强大的方法是按照所需的大小预分配比较大的相邻块(XFS 以前就是采用这种方法)。ext4 通过一个新的系统调用来实现这个目的,这个调用将按照特定的大小预分配并初始化文件。然后,您就可以写入必要的数据,并为数据提供不错的读性能。

    • 延迟块分配:
      另一个基于文件大小的优化是延迟分配。这种性能优化延迟磁盘上的物理块的分配,直到块被刷入到磁盘时才进行分配。这种优化的关键是延迟物理块的分配,直到需要在磁盘上写这些物理块时才对其进行分配并写到相邻的块。这类似于持久化预分配,惟一的区别是文件系统会自动执行这项任务。不过如果预先知道文件的大小时,持久化预分配是更好的选择。

    • 多个块分配:
      这是最后一个与相邻块相关的优化,即针对 ext4 的块分配器。在 ext3 中,块分配器的工作方式是每次分配一个块。当需要分配多个块时,非相邻块中可能存在相邻的数据。ext4 使用块分配器修复了这个问题,它能够在磁盘上一次分配多个块。与前面其他优化一样,这个优化在磁盘上收集相关的数据,以实现相邻读优化。

      多个块分配的另一个方面是分配块时需要的处理量。记住,ext3 一次只分配一个块。在最简单的情况下,每个块的分配都要有一个调用。如果一次分配多个块,对块分配器的调用就会大大减少,从而加快分配并减少处理量。

  • 更加可靠:
    日志记录就是通过日记(磁盘上相邻区域的专门循环记录)记录文件系统的变更的过程。因此,根据日志对物理存储执行实际变更更加可靠,并且能够确保一致性,即使在操作期间出现系统崩溃或电源中断。这样做可以减少文件系统损坏的几率。

    但是即使进行日志记录,如果日志出现错误仍然会导致文件系统损坏。为了解决这个问题,ext4 对日志执行校验和,确保有效变更能够在底层文件系统上正确完成。

  • 在线磁盘碎片整理:
    尽管 ext4 添加一些特性来减少文件系统的碎片(比如将相邻块分配为区段),但随着系统使用时间的增加,碎片是难以完全避免的。因此出现了在线碎片整理工具,它们可以对文件系统和单个文件执行碎片整理,从而改善性能。

总结

拓展文件系统发展到第4代,功能和性能优越毋容置疑,还在用ext3的都升级到4来吧~

参考链接:Linux文件系统 - 随笔分类 - AlanTu - 博客园 

你可能感兴趣的:(文件系统,linux)