Linux 磁盘与档案系统管理——认识 Linux 档案系统

认识 Linux 档案系统

Linux最传统的磁盘档案系统(filesystem)使用的是 EXT2,所以要了解 Linux 的档案系统就从 EXT2 开始。
而档案系统是建立在磁盘上面的,因此我们得了解磁盘的物理组成才行。


磁盘组成与分隔的复习

磁盘的物理组成,整个磁盘的组成主要有:

  • 圆形的磁碟盘(主要记录资料的部分);
  • 机械手臂,与在机械手臂上的磁盘读取头(可读写磁碟盘的上资料);
  • 主轴马达,可以转动磁碟盘,让机械手臂的读取头在磁碟盘上读写资料。

从上面我们可以知道资料存储与读取的重点在于磁碟盘,而磁碟盘的物理组成如图所示:

  • 磁区(Sector)为最小的物理存储单位,且依据瓷碟设计的不同,目前主要有 512bytes 与 4K 两种格式;
  • 将磁区组成一个圆,那就是磁柱(Cylinder);
  • 早期的分割主要以磁柱为最小分割单位,现在的分割通常使用磁区为最小分割单位(每个磁区都有其号码哦,就好像座位一样);
  • 磁碟分割表主要有两种格式,一种是限制较多的 MBR 分割表,一种是较新且限制较少的 GPT 分割表。
  • MBR 分割表中,第一个磁区最重要,里面有:(1)主要开机区(Master boot record,MBR)及分割表(partition table),其中 MBR 占有 446 bytes,而 partition table 则占有 64 bytes。
  • GPT 分割表除了分割数量扩充较多之外,支持的磁盘容量也可以超过 2TB。

磁盘的档名部分:

  • /dev/sd[a-p][1-128] :为实体磁盘的磁盘档名
  • /dev/vd[a-d][1-128] :为虚拟磁盘的磁盘档名
  • /dev/md[0-128] :软件磁盘阵列;
  • /dev/VGNAME/LVNAME :使用 LVM 时,档名则是这个(后面学习)

磁盘分割:
以前磁盘分割最小单位经常是磁柱,但 CentOS 7.x 的分割软件已经将最小单位改成磁区了,所以容量大小的分割可以切的更细。
由于新的大容量磁盘大多得要使用 GPT 分割表才能够使用全部的容量,因此过去的 MBR 的传统磁盘分割表限制就不会存在了。
不过,现在也是有小磁盘的,所以在处理分割的时候,还是需要先查询以下,分割是 MBR 还是 GPT 分割的。
后面的建议使用 GPT 分割表进行分割。


档案系统特点

我们都知道磁盘分割完毕后需要进行格式化(format),之后作业系统才能够使用这个档案。

为什么要进行格式化呢?
- 因为每种作业系统所设定的档案属性/权限并不相同,为了存放这些档案所需的资料,因此就需要将分割槽进行格式化,以称为作业系统能够利用的【档案系统格式(filesystem)】。

由此得知,每种作业系统能够使用的档案系统并不相同,例如:Windows 98 以前的微软产品主要是 FAT(或 FAT16),Windows 2000 以后的版本就有了所谓的 NTFS 档案系统,至于** Linux 的正统档案系统则为 Ext2(Linux second extended file system, ext2fs)**这一个。此外,预设情况下 Windows 不认识 Linux的 Ext2 。

传统的磁盘与档案系统应用中,一个分割槽就只能够被格式化成为一个档案系统,所以我们可以说一个 filesystem 就是一个 partition。
随着新技术的利用,例如我们常听到的 LVM 与软件磁盘阵列(software raid),这些技术可以将一个分隔槽格式化为多个档案系统(例如 LVM),也能够将多个分隔槽合成一个档案系统(LVM,RAID)。
目前我们在格式化时已经不在说成针对 partition 来格式化了,通常我们可以称呼一个可被挂在的资料为一个档案系统而不是一个分隔槽喔!

档案系统的运作:
这与作业系统的档案资料有关。
较新的作业系统的档案资料除了档案实际内容外,通常含有非常多的属性,例如 Linux 作业系统的档案权限(rwx)与档案属性(拥有者、群组、时间参数等等)。
档案系统通常会将这两部分的资料分别存放在不同的区块,权限与属性放置到 inode 中,至于实际资料则放置到 data block 区块中。
另外还有一个超级区块(superblock)会记录整个档案系统的整体资讯,包括 inode 与 block 的总量、使用量、剩余量等等。

每个 inode 与 block 都有编号,这单个资料的意义如下:

  • superblock:记录此 filesystem 的整体资讯,包括 inode/block 的总量、使用量、剩余量,以及档案系统的格式与相关资讯等;
  • inode:记录档案的属性,一个档案占用一个 inode,同时记录此档案的资料所在的 block 号码;
  • block:实际记录档案的内容,若档案太大时,会占用多个 block。

由于每个 inode 与 block 都有编号,而每个档案都会占用一个 inode, inode 内则有档案资料放置的 block 号码。
因此,我们可以知道如果能够找到档案的 inode ,就会知道这个档案所放置资料的 block 号码,当然也就能够读取该档案的实际资料了。
这是比较有效的做法,因为如此以来我们的磁盘就能够在短时间内读取出全部的资料,读写的效能会比较好。

如图:
档案系统先格式化出 inode 与 block 的区块,假设某一个档案的属性与权限资料放置到 inode 4 号,而这个 inode 记录了档案资料的实际放置位置为 2, 7, 13, 15 这四个 block 号码,此时我们的作业系统就能够据此来排列磁盘的读取顺序,可以一口气将四个 block 内容读出来。

这种资料存取的方法我们称为索引式档案系统(indexed allocation)

可以与这种资料存取方式比较一下的另一种方式,就是我们惯用的随身碟(快闪记忆体(u盘)),它使用的档案系统一般为 FAT 格式。
这种格式的档案系统并没有 inode 存在,所以 FAT 没有办法将这个档案的所有 block 在一开始就读取出来。
每个 block 号码都记录在一个 block 当中,它的读取方式有点像下图:

上图假设档案的资料依次写入 1-> 7-> 4-> 15 号,这四个 block 号码中,但这个档案系统没有办法一口气知道四个 block 的号码,它需要一个个的将 block 读出后,才会知道下一个 block 在哪里。
如果同一个档案资料写入的 block 分散的泰国厉害时,则我们的磁盘读取头将无法在磁盘转一圈就读到所有资料,因此磁头就会多转好几圈才能完整的读取这个档案的内容。

磁盘重组:
需要磁盘重组的原因就是档案写入的block 太过于离散了,此时档案读取的效能将会变的很差所致。
这个时候可以通过磁盘重组将同一个档案所属的 blocks 整合在一起,这样资料的读取会比较容易啊

通过上面我们可以知道 FAT 的档案系统隔三差五的就需要磁盘重组以下,那么 Ext2 是否需要磁盘重整呢?
- 因为 Ext2 是索引式档案系统,基本上不太需要常常进行磁盘重组的。但是如果档案系统使用太久,常常删除/编辑/新增档案时,还是有可能会造成档案资料泰国离散的问题,此时或许会需要进行重整以下的。
不过,自己用的 Linux 作业系统上面进行 Ext2/Ext3 档案系统的磁盘重组,几乎没有必要。


Linux 的 EXT2 档案系统(inode)

inode 的内容在记录档案的权限与相关属性,至于 block 区块则是在记录档案的实际内容。
而且档案系统一开始就将 inode 与 block 规划好了,除非重新格式化(或者利用 resize2fs 等指令变更档案系统大小),否则 inode 与 block 固定后就不会再变动。
但是,如果我的档案系统高达数百 GB 时,那么将所有的 inode 与 block 统统放置在一起将是很不明智的决定,因为 inode 与 block 的数量太庞大,不容易管理。
所以, Ext2 档案系统在格式化的时候基本上是区分为多个区块群组(block group)的,每个区块群组都有独立的 inode/block/superblock 系统。

如下图:

在整体的规划当中,大难系统最前面有一个开机磁区(boot sector),这个开机磁区可以安装开机管理程序,这是个非常重要的设计,因为如此一来我们就能够将不同的开机管理程序安装到个别的档案系统最前面,而不用覆盖磁盘唯一的 MBR,这样也才能够制作出多重开机的环境!
至于每个区块群组(block group)的留个主要内容说明如下:


data block(资料区块)

data block 是用来放置档案内容资料的地方。
在 Ext2 档案系统中所支持的 block 大小有 1K、2K、4K 三种。
格式化时 block 的大小就固定了,且每个 block 都有编号,以方便 inode 的记录。
需要注意:由于 block 大小的差异,会导致该档案系统能够支持的最大磁盘容量与最大单一档案容量并不相同。因为 block 大小而产生的 Ext2 档案系统限制如下:

Block 大小 1KB 2KB 4KB
最大单一档案限制 16GB 256GB 2TB
最大档案系统总容量 2TB 8TB 16TB

需要注意的是,虽然 Ext2 已经能够支持大于 2GB 以上的单一档案容量,不过某些应用程序依然使用旧的限制,也就是说,某些程序只能够捉到小于 2GB 以下的档案而已,这就跟档案系统无关了!

除此之外 Ext2 档案系统的 block 还有如下基本限制:

  • 原则上,block 的大小与数量在格式化完成就不能够再改变了(除非重新格式化)
  • 每个 block 内最多只能够放置一个档案的资料
  • 承上,如果档案大于 block 的大小,则一个档案会占用多个 block 数量
  • 承上,如果档案小于 block ,则该 block 的剩余容量就不能够再被使用了(磁盘空间会被浪费)

如上所述,因为每个 block 仅能容纳一个档案的资料而已,因此如果你的档案都非常小,但是你的 block 在格式化时却选用了最大的 4K 时,可能会产生一些容量的浪费。
例如:BBS 网站的资料,使用纯文字档案记载每篇留言等等场景。

既然大的 block 可能会产生严重的磁盘容量的浪费,那么我们是否就将 block 大小定为 1K 即可?这也不妥,因为如果 block 较小的化,那么大型档案将会占用数量更多的 block,而 inode 也要记录更多的 block 号码,此时将可能导致档案系统不良的读写效能。

所以我们可以说,在进行档案系统格式化之前,需要先想好档案系统预计使用情况。

事实上,现在的磁盘容量都太大了,所以,大概大家都只会选择 4k 的 block 大小吧。


inode table(inode 表格)

前面说,inode 的内容在记录档案的属性以及档案实际资料是放置在哪几号 block 内,基本上,inode 记录的档案资料至少有如下几项:

  • 该档案的存取模式(read/write/excute)
  • 该档案的拥有者与群组(owner/group)
  • 该档案的容量
  • 该档案建立或状态改变的时间(ctime)
  • 最近一次读取时间(atime)
  • 最近修改的时间(mtime)
  • 定义档案特定的旗标(flag),如 SetUID...
  • 该档案真正内容的指向(pointer)

inode 的数量与大小也是在格式化时就已经固定了,除此之外 inode 还有些什么特点呢?

  • 每个 inode 大小均固定为 128 bytes(新的 ext4 与 xfs 可设定到 256 bytes)
  • 每个档案都仅会占用一个 inode 而已
  • 承上,因此档案系统能够建立的档案数量与 inode 的数量有关
  • 系统刦档案时需要先找到 inode,并分析 inode 所记录的权限与使用者是否符合,若符合才能够开始实际读取 block 的内容。

来简单分析以下 EXT2 的 inode/block 与档案大小的关系。
inode 要记录的资料非常多,但偏偏只有 128bytes 而已,而 inode 记录一个 block 号码要花掉 4bytes,假设我一个档案有 400M 且每个 block 为 4K 时,那么至少要 10万个block 号码才能记录得下,inode 哪里有那么多空间呢?
因此系统很聪明的将inode 记录 block 号码的区域定义为 12 个直接,一个间接,一个双间接与一个三间接记录区。
如下所示:

如图,左边 inode 本身(128bytes),里面有12个直接指向 block 号码的对照,这12个是可以直接取得 block 号码的。至于所谓的间接就是再拿一个 block 来当做记录 block 号码的记录区,如果档案太大时,就会使用间接的 block 来记录号码。如果档案持续长大,那就会利用所谓的双间接,第一个 block仅指出下一个记录号码的 block 在哪里,实际资料的block号码是记录在第二个block中。一次类推,三间接就是利用第三层 block 来记录号码。

那么,这样子 inode 能够指定多少个 block 呢? 我们以较小的 1K block 来说明好了,可以指定的情况如下:

  • 12个直接指向:12*×1K=12K
    • 由于是直接指向,所以总共可以记录 12比记录,因此总大小就如上所示;
  • 间接:256*1K=256K
    • 每笔 block 号码的记录会花去 4bytes,因此 1K 的大小能够记录 256 比记录,因此一个间接可以记录的大小如上;
  • 双间接:256×256×1K=256²K
    • 第一层 block 会指定 256 个第二层,每个第二层可以指定 256 个号码,因此总额大小如上;
  • 三间接:256256256*1K=256³K
    • 第一层 block 会指定 256 个第二层,每个第二层会指定 256 个第三层,每个第三层可以指定256个号码,因此总额大小如上;
  • 总额:将直接、间接、双间接、三间接相加,得到 12 + 256 + 256256 + 256256*256 (K) = 16GB

此时我们知道档案系统将 block 格式化为 1K 大小时,能够容纳的最大档案为 16GB,比较档案系统限制表的结果是一致的。
但是这个方法不能用在 2K 和 4K block 大小的计算中,因为大于 2K 的block 将会受到 Ext2 档案系统本身的限制,所以计算的结果会不太符合。

Tips:如果你的 Linux 依舊使用 Ext2/Ext3/Ext4 檔案系統的話,例如鳥哥之前的 CentOS 6.x 系統,那麼預設還是使用 Ext4 的檔案系統喔! Ext4 檔案系統的 inode 容量已經可以擴大到 256bytes 了,更大的 inode 容量,可以紀錄更多的檔案系統資訊,包括新的 ACL 以及 SELinux 類型等, 當然,可以紀錄的單一檔案容量達 16TB 且單一檔案系統總容量可達 1EB 哩!


Superblock(超级区块)

Superblock 是记录整个 filesystem 相关资讯的地方,没有 Superblock,就没有这个 filesystem 了。
它记录的信息主要有:

  • block 与 inode 的总量
  • 为使用与已使用的 inode / block 数量
  • block 与 inode 的大小(block 为 1,2,4K,inode 为 128bytes 或 256bytes)
  • filesystem 的挂在时间、最近一次写入资料的时间、最近一次检验磁盘(fsck)的时间等档案系统的相关资讯
  • 一个 valid bit 数值,若次档案系统一杯挂在,则 valid bit 为 0 ,若未被挂在,则 balid bit 为 1 。

Superblock 是非常重要的,因为我们这个档案系统的基本资讯都写在这里,因此,如果 superblock 死掉了,你的档案系统可能就需要话费很多时间取挽救了!一般来说, superblock 的大小为 1024bytes。相关的 superblock 信息我们可以 dumpe2fs 指令来观察。

此外,每个 block group都可能含有 superblock 哦。但是我们也说一个档案系统应该仅有一个 superblock 而已,这是怎么回事呢?事实上除了第一个 block group 内会含有 superblock 之外,后续的 block group 不一定含有 superblock,若是含有 superblock 则该superblock 主要是为第一个 block group 内 superblock 的备份,这样可以进行 superblock 的救援。


Filesystem Description(档案系统描述说明)

这个区段可以描述每个 block group 的开始与结束的 block 号码,以及说明每个区段(superblock, bitmap, inodemap, data block)分别介于哪一个 block 号码之间。这部分也在 dumpe2fs学吧。


block bitmap(区块对照表)

如果你想要新增档案时总会用到 block 吧!那你要使用哪个 block 来记录呢?当然是选择【空的 block】来记录新档案的资料喽。
那你怎么知道哪个 block 是空的?这就得要通过 block bitmap 的辅助了。
从 block bitmap 当中可以知道那些 block 是空的,因此我们的系统就能够很快速的找到可使用的空间来处置档案喔。

同样的,如果你删除某些档案时,那么那些档案原本占用的 block 号码就得要释放出来,此时在 block bitmap 当中向对应到该 block 号码的标志就得要修改称为【未使用中】喽,这就是 bitmap 的功能。


inode bitmap(inode 对照表)

这个其实与 block bitmap 是类似的功能,只是 block bitmap 记录的是使用与未使用的 block 号码,至于 inode bitmap 则是记录使用与未使用的 inode 号码喽!


dumpe2fs:查询 Ext 家族 superblock 信息的指令

了解档案系统的概念之后,就需要观察这个档案系统了。我们知道了各部分资料都与 block 号码有关!
每个区块与 superblock 的信息都可以使用 dumpe2fs 这个指令来查询的。
不过比较可续的是,CentOS 7 是 xfs 为预设档案系统,无法使用 dumpe2fs 查看任何档案系统的。
不过没关系,在学习过后续的格式化内容后,可以自己切出一个 ext4 的大难系统查询看看。

[root@study ~]# dumpe2fs [-bh] 裝置檔名
選項與參數:
-b :列出保留為壞軌的部分(一般用不到吧!?)
-h :僅列出 superblock 的資料,不會列出其他的區段內容!

範例:鳥哥的一塊 1GB ext4 檔案系統內容
[root@study ~]# blkid   <==這個指令可以叫出目前系統有被格式化的裝置
/dev/vda1: LABEL="myboot" UUID="ce4dbf1b-2b3d-4973-8234-73768e8fd659" TYPE="xfs"
/dev/vda2: LABEL="myroot" UUID="21ad8b9a-aaad-443c-b732-4e2522e95e23" TYPE="xfs"
/dev/vda3: UUID="12y99K-bv2A-y7RY-jhEW-rIWf-PcH5-SaiApN" TYPE="LVM2_member"
/dev/vda5: UUID="e20d65d9-20d4-472f-9f91-cdcfb30219d6" TYPE="ext4"  <==看到 ext4 了!

[root@study ~]# dumpe2fs /dev/vda5
dumpe2fs 1.42.9 (28-Dec-2013)
Filesystem volume name:   <none>           # 檔案系統的名稱(不一定會有)
Last mounted on:          <not available>  # 上一次掛載的目錄位置
Filesystem UUID:          e20d65d9-20d4-472f-9f91-cdcfb30219d6
Filesystem magic number:  0xEF53           # 上方的 UUID 為 Linux 對裝置的定義碼
Filesystem revision #:    1 (dynamic)      # 下方的 features 為檔案系統的特徵資料
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent 64bit 
 flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr acl   # 預設在掛載時會主動加上的掛載參數
Filesystem state:         clean            # 這塊檔案系統的狀態為何,clean 是沒問題
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              65536            # inode 的總數
Block count:              262144           # block 的總數
Reserved block count:     13107            # 保留的 block 總數
Free blocks:              249189           # 還有多少的 block 可用數量
Free inodes:              65525            # 還有多少的 inode 可用數量
First block:              0
Block size:               4096             # 單個 block 的容量大小
Fragment size:            4096
Group descriptor size:    64
....(中間省略)....
Inode size:               256              # inode 的容量大小!已經是 256 了喔!
....(中間省略)....
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      3c2568b4-1a7e-44cf-95a2-c8867fb19fbc
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             32M              # Journal 日誌式資料的可供紀錄總容量
Journal length:           8192
Journal sequence:         0x00000001
Journal start:            0

Group 0: (Blocks 0-32767)                  # 第一塊 block group 位置
  Checksum 0x13be, unused inodes 8181
  Primary superblock at 0, Group descriptors at 1-1   # 主要 superblock 的所在喔!
  Reserved GDT blocks at 2-128
  Block bitmap at 129 (+129), Inode bitmap at 145 (+145)
  Inode table at 161-672 (+161)                       # inode table 的所在喔!
  28521 free blocks, 8181 free inodes, 2 directories, 8181 unused inodes
  Free blocks: 142-144, 153-160, 4258-32767           # 底下兩行說明剩餘的容量有多少
  Free inodes: 12-8192
Group 1: (Blocks 32768-65535) [INODE_UNINIT]          # 後續為更多其他的 block group 喔!
....(底下省略)....
# 由於資料量非常的龐大,因此鳥哥將一些資訊省略輸出了!上表與你的螢幕會有點差異。
# 前半部在秀出 supberblock 的內容,包括標頭名稱(Label)以及inode/block的相關資訊
# 後面則是每個 block group 的個別資訊了!您可以看到各區段資料所在的號碼!
# 也就是說,基本上所有的資料還是與 block 的號碼有關就是了!很重要!

利用 dumpe2fs 可以查询到非常多的信息,不过依照内容主要可以区分为:
上半部分是 superblock 内容,下半部分是每个 block group 的信息。从上面的表格可以观察 /dev/vad5 规划的 block 为 4K,第一个 block 号码为 0 号,且 block group 内的所有信息都以 block 的号码来表示的,然后 superblock 中还有谈到目前这个档案系统的可用 block 与 inode 数量。

至于 block group 的内容我们单纯看 Group0 信息好了。从上表可以发现:

  • Group0 所占用的 block 号码由 0 到 32767 号, superblock 则在第 0 号 的 block 区块内!
  • 档案系统描述说明在 1 号 block 中;
  • block bitmap 与 inode bitmap 则在 129 及 145 的 block 号码上。
  • 至于 inode table 分布于 161-172 的 block 号码中;
  • 由于:
    • 1.一个 inode 占用 256 bytes,
    • 2.总共有 672-161+1(161本身)=512个block花在 inode table上;
    • 3.每个block的大小为 4096 bytes(4K)。
    • 有这些数据可以算出 inode 的总量共有 512*4096/256=8192 个 inode 了。
  • 这个 Group0 目前可用的 block 有 28521 个,可用的 inode 有 8181 个;
  • 剩余 inode 号码为 12 号到 8192 号。

档案系统学到这里应该就差不多了,如果需要了解更多就自行搜索资料吧。


与目录树的关系

我们知道了,在 Linux 系统下,每个档案(无论档案还是目录)都会占用一个 inode,且可依据档案内容的大小来分配多个 block 给档案使用。
我们知道,目录的内容在记录档名,一般档案才是实际记录资料内容的地方。
那么目录与档案在档案系统中是如何记录资料的呢?


目录

当我们在linux下的档案系统建立一个目录时,档案系统会分配一个 inode 与 至少一块 block 给该目录.
其中,inode 记录该档案的相关权限与属性,并可记录分配到的那块 block 号码;
而 block 则是记录在这个目录下的档名与该档名占用的 inode 号码资料。

也就是说,目录所占用的 block 内容在记录以下信息:


记载于目录所属的 block 内的档名与 inode 号码对应示意图

如果想要实际观察 root 家目录内的档案所占用 inode 号码时,可以使用 ls -i这个选项。
因为每个人的电脑不同,系统安装时选择的项目与 partition 都不一样,因此和别人电脑显示的 inode 号码可能会不同,正常。
当我们使用 ll 时,出现的目录大小几乎都是1024的倍数,因为每个 block 的数量都是 1K,2K,4K 呀。
有个奇怪的目录 /proc 占用空间是 0 ,因为前面就学过这个目录是不占用磁盘空间的啊.

Tips:经过上面的知识可以知道,目录并不只会占用一个 block 而已,也就是说,在目录底下的档案数量如果太多了而导致一个 block 无法容下所欲的档名与 inode 对照表时,Linux 会给予该目录多一个 block 来继续记录相关的资料。


档案:

当我们在 Linux 下的 ext2 建立一个一般档案时, ext2 会分配一个 inode 与相对于该档案大小的 block 数量给该档案。
例如:假设我的一个 block 为 4 Kbytes,而我要建立一个 100 K 的档案,那么 Linux 将分配一个 inode 与 25 个 block 来存储该档案!但是,由于 inode 仅有 12 个直接指向,因此还要多一个 block 来作为区块号码的记录哦。


目录树读取:

经过上面的说明,我们知道 inode 本身并不记录档名,档名的记录是在目录的 block 当中。
因此,我们在档案目录与权限说明中,才会提到【新增/删除/更名档名与目录的 w 权限有关】的特点。
因为档名是记录在目录的 block 当中,因此当我们要读取某个档案时,就一定会经过目录的 inode 与 block,然后才能够找到那个待读取档案的 inode 号码,最终才会读到正确的大难的 block 内的资料。

由于目录树是有根目录开始读起的,因此系统通过挂在的信息可以找到挂载点的 inode 号码,此时就能够得到根目录的 inode 内容,并依据 inode 读取根目录的 block 内的档名资料,再一层一层的往下读到正确的档名。

例如, /etc/passwd 这个档案,系统如何读取的?

[root@study ~]# ll -di / /etc /etc/passwd
     128 dr-xr-xr-x.  17 root root 4096 May  4 17:56 /
33595521 drwxr-xr-x. 131 root root 8192 Jun 17 00:20 /etc
36628004 -rw-r--r--.   1 root root 2092 Jun 17 00:20 /etc/passwd

读取该档案流程为(假设读取者身份为一般身份的使用者):

  1. / 的 inode:
    • 通过挂在点的信息找到 inode 号码为 128 的根目录 inode ,且 inode 规定的权限让我们可以读取 block 的内容(有 r 与 x):
  2. / 的 block:
    • 经过上个步骤取得 block 的号码,并找到该内容有 etc/ 目录的 inode(33595521);
  3. etc/ 的 inode:
    • 读取 33595521 号 inode 得知 hare 有 r 与 x 的权限,因此可以读取 etc/ 的block 内容;
  4. etc/ 的 block:
    • 经过上个步骤取得 block 号码,并找到该内容有 passwd 档案的 inode 号码(36628004);
  5. passwd 的 inode:
    • 获取 36628004 号 inode 得知 hare 具有 r 的权限,因此可以读取 passwd 的 block 内容;
  6. passwd 的 block:
    • 最后将该 block 内容的资料读出来。

filesystem 大小与磁盘读取效率:

关于档案系统的使用效率上,当你的一个档案系统规划的很大时,例如 100GB ,由于磁盘上面的资料总是来来去去的,所以整个档案系统上面的档案通常无法连续卸载一起(block号码不会连续的意思),而是填入式的将资料填入没有被使用的 block 当中。如果档案写入的 block 真的很分散,此时就会有所谓的档案资料离散的问题产生了。

虽然我们的 ext2 在 inode 处已经将该档案所记录的 block 号码都记录上了,所以资料可以一次性读取,但是如果档案太过离散,的确还是会发生读取效率低下的问题。因为磁盘读取头还是得要在整个档案系统中来来回回的频繁读取。
果真如此,那么可以将整个 filesystem 内的资料全部复制出来,将该 filesystem 重新格式化,在将资料给复制回去就可以解决这个问题。

此外,如果 filesystem 真的太大了,那么当一个档案分别记录在这个档案系统的最前面与最后面的 block 号码中,此时会造成磁盘的机械手臂移动幅度过大,也会造成资料读取效率低下。而且读取头在搜索整个 filesystem 时,也会花费比较多的时间。因此 partition 的规划并不是越大越好,而是真的要针对你主机的用途来进行规划才好。
以上两段都是针对机械硬盘的哦


EXT2/EXT3/EXT4 档案的存取与日志式档案系统的功能

上一节只是讲到了读取而已,那么如果是新建一个档案或目录时,我们的档案系统是如何处理的呢?
这时就需要 block bitmap 及 inode bitmap 的帮忙了。

假设我们想要新增一个档案,此时档案系统的行为是:

  1. 先确定使用者对于新增档案的目录是否具有 w 与 x 的权限,若有的话才能新增;
  2. 根据 inode bitmap 找到没有使用的 inode 号码,并将新档案的权限/属性写入;
  3. 根据 block bitmap 找到没有使用中的 block 号码,并将实际的资料写入 block 中,且更新 inode 的 block 指向资料;
  4. 将刚刚写入的 inode 与 block 资料同步更新 inode bitmap 与 block bitmap,并更新 superblock 的内容。

一般来说,我们将 inode table 与 data block 称为资料存放区域,至于其他例如 superblock 、block bitmap 与 inode bitmap 等区域段就别称为 metadata(中介资料),因为superblock,inode bitmap及 block bitmap 的资料是经常变动的,每次新增、移除、编辑时都可能会影响到这三部分的资料,因此才被称为中介资料


资料的不一致(Inconsistent)状态

在一般正常情况下,上述的新增动作当然可以顺利的完成。
但是如果万一遇到了不知名原因导致系统中断(例如停电、系统核心发生错误等等)的时候,写入的资料仅有 inode table 及 data block 而已,最后一个同步更新中介资料的步骤并没有做完,此时就会发生 metadata 的内容与实际资料存放区不一致(Inconsistent)的情况了。

既然有不一致淡然就得要克服,早期在 Ext2 档案系统中,如果发生这个问题,那么系统在重新开机时,就会藉由 superblock 当中记录的 valid bit(是否有挂在)与 filesystem state(clean 与否)等状态来判断是否强制进行资料一致性的检查。若有需要检查时则以 【e2fsck】 这个程序来进行。

不过,这样的检查比较费时,因为要针对 metadata 区域与实际资料存放区来进行比对,要搜索整个 filesystem ,如果档案系统有 100GB 以上,里面的档案数量有多时,系统就有的忙了。而且在对 Internet 踢欧冠呢服务的服务器主机上面,这样的检查真的会造成主机复原时间的拉长,很麻烦。
这也就造成了所谓的日志式档案系统的兴起了。


日志式档案系统(journaling filesystem)

为了避免上述提到的档案系统不一致的情况发生,因此我们的前辈们想到一个方式,如果在我们的 filesystem 当中规划出一个区块,该区块专门在记录写入或修订档案的步骤,那不就可以简化一致性检查的步骤了?
也就是说:

  1. 预备:当系统要写入一个档案时,会先在日志记录区块中记录某个档案准备要写入的信息;
  2. 实际写入:开始写入档案的权限与资料;开始更新 metadata 的资料;
  3. 结束:完成资料与 metadata 的更新后,在日志记录区块当中完成该档案的记录。

在这样的程序当中,万一资料的记录过程当中发生了问题,那么我们的系统只要取检查日志记录区块,就可以知道哪个档案发生了问题,针对该问题来做一致性的检查即可,而不必针对整块 filesystem 去检查,这样就可以达到快速修复 filesystem 的能力了!这就是日志式档案最基础的功能。

那我们的 ext2 可以达到这样的功能吗?当然, ext4/ext3 是 ext2 的升级版本,所以建议直接使用 ext4 这个filesystem 。
再看看之前的 dumpe2fs 输出的信息:

Journal inode:            8
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             32M
Journal length:           8192
Journal sequence:         0x00000001

通过 inode 8 号记录 journal 区块的 block 指向,而且具有 32MB 的容量在处理之日呢。
日志,就是干这个的喽。


Linux 档案系统的运作

了解了目录树与档案系统的关系了,但是我们也知道资料都得要载入到内存后 CPU 才能够进行处理,如果我常常编辑一个好大的档案,在编辑的过程中又频繁的要系统写入到磁盘中,由于磁盘写入的速度要比内存慢很多,因此会常常会耗在等待磁盘的写入/读取上。效率很低。

为了解决这个效率问题,我们的 Linux 使用的方式是通过一个称为非同步处理(asynchronously)的方式。
所谓的非同步处理是这样的:

当系统在日一个档案到内存后,如果该档案内有被更动过,则在内存区段的档案资料会被设定为干净(clear)的。但如果内存中的档案被更改过了(例如用vim编辑过),此时内存中的资料会被设定为脏的(dirty)。此时所有的动作都还在内存中执行,并没有写入到磁盘中.系统会不定时的将内存中设定为【dirty】的资料写回磁盘中,以保持磁盘记忆资料的一致性。当然也可以使用 sync 指令来手动强迫写入磁盘

我们知道内存的速度比磁盘快,因此如果能够将常用的档案放置到内存中,这不就会增加系统性能吗?
没错,室友这样的想法,因此我们 linux 系统上面档案系统与内存有非常大的关系:

  • 系统会将常用的档案资料放置到主记忆体的缓冲区,以加速档案系统的读/写;
  • 承上,因此 linux 的实体内存最后都会被用光,这是正常的情况,可加速系统效能;
  • 你可以手动使用 sync 来强迫内存中设置为 dirty 的档案写回到磁盘中;
  • 若正常关机时,关机指令会主动呼叫 sync 来将内存的资料写回磁盘内;
  • 但若不正常关机(如跳电、宕机或其他不明原因),由于资料尚未回写到磁盘内,因此重新开机后可能会花很多时间在进行磁盘检查,甚至可能导致档案系统的虽会(非磁盘损坏)。

挂载点的意义(mount point)

每个 filesystem 都有独立的 inode / block / superblock 等信息,这个档案系统要能够连接到目录树才能够被我们使用。
将档案系统与目录树结合的动作我们称为【挂载】。
重点:挂载点一定是目录,该目录为进入该档案系统的入口。
因此并不是你有任何档案系统都能使用,必须要【挂载】到目录树的某个目录后,才能够使用该档案系统。

例如,我们在安装 CentOS 7.x 的时候,应该有三个挂载点,分别是 /, /boot, /home三个 如果观察这三个目录的 inode 会发下:

[root@study ~]# ls -lid / /boot /home
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /
128 dr-xr-xr-x.  4 root root 4096 May  4 17:59 /boot
128 drwxr-xr-x.  5 root root   41 Jun 17 00:20 /home

由于 XFS filesystem 最顶层的目录值 inode 一般为 128 号(可能有不同),因此可以发现 / ,/boot, /home 为三个不同的 filesystem 了。
之前学过,根目录的 . 与 .. 是相同的东西,因为权限是一模样的,如果使用档案系统的观点来看,同一个 filesystem 的某个 inode 只会对应到一个档案内容而已(因为一个档案占用一个 inode),因此我们可以通过判断 inode 号码来确认不同档名是否为相同的档案:

[root@study ~]# ls -ild /  /.  /..
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /.
128 dr-xr-xr-x. 17 root root 4096 May  4 17:56 /..

上面信息显示,由于挂载点都是 / ,所以这三个档案都在一个 filesystem 内,而这三个档案的 inode 号码都是 128 号,因此这三个档名都指向同一个 inode 号码。当然这个档案的内容也就完全一样了,也就是说 / 的上层目录就是它自己。


其他 Linux 支持的档案系统与 VFS

虽然 Linux 的标准档案系统是 ext2,且还有增加了日志功能的 ext3/ext4 ,事实上,Linux 还有支持很多档案系统格式,尤其是最近这几年退出了好几种速度很快的日志式档案系统, 包括 SGI 的 XFS 档案系统,可以适用于小型档案的 Reiserfs 档案系统,以及 Windows 的 FAT 档案系统等等,都能够被 Linux 所支持。
常见的支持档案系统有:

  • 传统档案系统:ext2/minix/MS-DOS/FAT(用 vfat 模组)/ iso9660(光盘)等等;
  • 日志式档案系统:ext3 / ext4 / ReiserFS / Windows'NTFS / IBM's JFS / SGI's XFS / ZFS
  • 网络档案系统:NFS / SMBFS

想要知道你的 Linux 支持的档案系统有那些,可以查看这个目录:ls -l /lib/modules/S(uname -r)/kernel/fs
系统目前已载入到内存中支持的档案系统有:cat /proc/filesystems


Linux VFS(Virtual Filesystem Switch)

Linux 核心是如何管理这些认识的档案系统呢?其实,整个 Linux 的系统都是通过一个名为 Virtual Filesystem Switch 的核心功能去读取 filesystem 的。
也就是说,整个 Linux 认识的 filesystem 其实都是 VFS 在进行管理,我们使用者并不需要知道每个 partition 上头的 filesystem 是什么。(VFS 会主动帮我们做好读取的动作的)

假设你的根 / 使用的是 /dev/hda1,用 ext3 ,而 /home 使用 /dev/hda2, 用 reiserfs,那么你取用 /home/hare/.bashrc 时,有特别指定要用什么档案系统的模组来读取吗?应该没有吧,这就是 VFS 的功能了。
通过 VFS 的功能来管理所有的 filesystem ,省去我们需要自行设定读取档案系统的定义,方便很多,如图:

档案系统不是很容易理解的,可以自行搜索相关资料补充。


XFS 档案系统简介

从 CentOS 7 开始,预设的档案系统已经从原来的 ext4 变成 XFS 档案系统了。为啥呢?


EXT 家族当前较为伤脑筋的地方:支持度广,但格式化超慢!

Ext 档案系统家族对于档案格式化的处理方面,采用的是预先规划处所有的 inode/block/meta data 等资料,未来系统可以直接取用,不需要再进行动态配置的做法。这个做法在早期磁盘容量不打的时候还好,但是现在磁盘容量越来越大,连传统的 MBR 都已经被 GPT 所取代了,你可以想象一下,档你的 TB 级别的传统 ext 家族档案系统在格式化的时候,光是系统要预先分配 inode 与 block 就要消耗你好多的人类时间了。。。

另外,由于虚拟化应用越来越广泛,而作为虚拟化磁盘来源的巨型档案(单一档案好几个 GB 以上)也就越来越常见了。这种巨型档案在处理上需要考虑到效能的问题,否则虚拟磁盘的效率就会不太好,因此 CentOS 7 开始,档案系统已经由预设的 Ext4 变成 xfs 这个比较适合高容量磁盘巨型档案效能较佳的档案系统了。


XFS 档案系统的配置

基本上 xfs 就是一个日志式档案系统,而 CentOS 7.x 那他当做预设档案系统,自然就因为最早之前,这个 xfs 就是被开发出来用于高容量磁盘以及高性能档案系统之用。
因此,相当适合现在的系统环境,此外,几乎所有 Ext4 档案系统的功能,xfs 都可以具备。

xfs 档案系统在资料的分布上,主要规划为三个部分,一个资料区(data section)、一个档案系统活动登录区(log section)以及一个即时运作区(realtime section)。这三个区域的资料内容如下:

  • 资料区(data section)

    • 基本上,资料区就是跟我们之前谈到的 ext 家族一样, 包括 inode/data block/superblock 等资料,都放在这个区块,这个资料区与 ext 家族的 block group 类似,也是分为多个储存区群组(allocation groups)来分别放置档案系统所需要的资料。每个储存区群组都包含了(1)整个档案系统的 superblock (2)剩余空间的管理机制(3)inode的分配与追踪。此外,inode与block都是系统需要用到时,才动态分配产生的,所以格式化动作非常快!
    • 另外,与 ext 家族不同的是, xfs 的 block 与 inode 有多种不同的容量可供设定,block 容量可由 512bytes~64K 调配,不过,Linux 的环境下,由于内存控制的关系(分页档 pagesize 的容量之故),因此最高可以使用的 block 大小为 4K 而已!(鸟哥说尝试格式化 block 称为 16K 没问题,但是Linux核心不给挂在,所以也没办法使用)至于 inode 容量可由 256bytes 到 2M 这么大!不过,大概是保留 256bytes 的预设值就很够用了!
    • Tips:总之,xfs 的这个资料区的存储群组(allocation groups,AG),可以将他想成是 ext 家族的 block 群组(block groups)就对了。只是 inode 与 block 是动态产生并非一开始格式化就完成配置的。
  • 档案系统活动登录区(log section)

    • 这个区域主要被用来记录档案系统的变化,其实有点像日志区。档案的变化会在这里记录下来,直到该变化完整的写入到资料区后,该笔记录才会被终结。如果档案系统因为某些缘故(例如停电)而损毁时,系统会拿这个登录区块来进行检验,看看系统挂掉之前,档案系统正在运作些啥动作,藉以快速的修复档案系统。
    • 因为系统所有动作的时候都会在这个区块做个记录,因此这个区块的磁盘活动是相当频繁的。 xfs 设计优点有趣,在这个区域中,可以指定外部的磁盘来作为 xfs 档案系统的日志区块。例如,可以将 SSD 磁盘作为 xfs 的登录区,这样当系统需要进行任何活动,就可以更快速的进行工作!
  • 即时运作区(realtime section)

    • 当有档案要被建立时,xfs 会在这个区段里面找一个到数个的 extent 区块,将档案放置在这个区块内,等到分配完毕后,再写入到 data section 的 inode 与 block 去。这个 extent 区块的大小得要在格式化的时候就先指定,最小是 4K 最大可到 1G。一般非磁盘阵列的磁盘预设为 64K 容量,而具有类似磁盘阵列的 stripe 情况下,则建议 extent 设定为与 stripe 一样大较好。这个 extent 最好不要乱动,因为可能会影响到实体磁盘的效能。

XFS 档案系统的描述资料观察

刚了解了这么多,那有没有像 EXT 家族的 dumpe2fs 去观察 superblock 内容的相关指令可以查询呢?
xfs_info这个就可以了。

[root@study ~]# xfs_info 掛載點|裝置檔名

範例一:找出系統 /boot 這個掛載點底下的檔案系統的 superblock 紀錄
[root@study ~]# df -T /boot
Filesystem     Type 1K-blocks   Used Available Use% Mounted on
/dev/vda2      xfs    1038336 133704    904632  13% /boot
# 沒錯!可以看得出來是 xfs 檔案系統的!來觀察一下內容吧!

[root@study ~]# xfs_info /dev/vda2
1  meta-data=/dev/vda2         isize=256    agcount=4, agsize=65536 blks
2           =                  sectsz=512   attr=2, projid32bit=1
3           =                  crc=0        finobt=0
4  data     =                  bsize=4096   blocks=262144, imaxpct=25
5           =                  sunit=0      swidth=0 blks
6  naming   =version 2         bsize=4096   ascii-ci=0 ftype=0
7  log      =internal          bsize=4096   blocks=2560, version=2
8           =                  sectsz=512   sunit=0 blks, lazy-count=1
9  realtime =none              extsz=4096   blocks=0, rtextents=0

上面的输出信息可以这样解释:

  • 第一行里面的 isize 指的是 inode 的容量,每个 256bytes 这么大。至于 agcount 则是前面谈到的储存区群组(allocation group)的个数,共有 4 个,agsize 则是指每个储存群组具有 65536 个 block。配合第 4 行的 block 设定为 4K,因此整个档案系统的容量应该是 4655364K 这么大。
  • 第2行里面 sectsz 指的是编辑磁区(sector)的容量设定为 512bytes 这么大的意思。
  • 第4行里面的 bsize 指的是 block 的容量,每个 block 为 4K 的意思,共有 262144 个 block 在这个档案系统内。
  • 第5行里面的 sunit 与 swidth 与磁盘阵列的 stripe 相关性较高。
  • 第7行里面的 internal 指的是这个登录区的位置在档案系统内,而不是外部设备的意思。且占用了 4K×2560 个 block,总过约 10M 的容量。
  • 第9行里面的 realtime 区域,里面的 extent 容量为 4K 。不过目前没有使用。

由于上述例子并没有使用磁盘阵列,因此上头这个装置里头的 sunit 与 extent 就没有额外的指定特别的值。根据 xfs(5) 的说明,这两个值会影响到你的档案系统性能,所以格式化的时候要特别留意。(上面的说明,大致看看即可)

hare
2020.3.13

posted @ 2020-03-13 18:40  hare1925  阅读(731)  评论(0编辑  收藏  举报