为了调到中央配送中心,我会定期去多家大公司(主要是圣彼得堡和莫斯科)面试 DevOps 职位。 我注意到很多公司(很多优秀的公司,例如 Yandex)都会问两个类似的问题:
- 什么是索引节点;
- 什么原因会导致磁盘写入错误(或者例如:为什么可能会耗尽磁盘空间,本质是一样的)。
正如经常发生的那样,我确信我很了解这个主题,但当我开始解释时,知识差距就变得明显了。 为了系统化我的知识,填补空白,不再让自己难堪,我写这篇文章,也许对其他人有用。
我将从底部开始,即来自硬盘驱动器(我们将丢弃闪存驱动器、SSD 和其他现代设备;例如,让我们考虑任何 20 或 80 GB 的旧驱动器,因为块大小为 512 字节)。
硬盘驱动器不知道如何逐字节寻址其空间;它被有条件地划分为块。 块编号从0开始。(这称为LBA,详细信息在这里:
从图中可以看出,我将LBA块指定为HDD级别。 顺便说一句,您可以这样查看磁盘的块大小:
root@ubuntu:/home/serp# blockdev --getpbsz /dev/sdb
512
上面的一层是一个分区,一个分区用于整个磁盘(同样是为了简单起见)。 最常见的是使用两种类型的分区标记:msdos 和 gpt。 因此,msdos 是一种旧格式,支持高达 2Tb 的磁盘,gpt 是一种新格式,能够寻址高达 1 ZB 的 512 字节块。 在我们的例子中,我们有一个 msdos 类型的分区,从图中可以看出,该分区从 1 号块开始,而 MBR 使用零。
在第一个分区中我创建了一个ext2文件系统,它的默认块大小是4096字节,这也在图中有所体现。 您可以这样查看文件系统块大小:
root@ubuntu:/home/serp# tune2fs -l /dev/sdb1
tune2fs 1.42.9 (4-Feb-2014)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: a600bf40-f660-41f6-a3e6-96c303995479
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: ext_attr resize_inode dir_index filetype sparse_super large_file
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 65536
Block count: 261888
Reserved block count: 13094
Free blocks: 257445
Free inodes: 65525
First block: 0
Block size: 4096
Fragment size: 4096
Reserved GDT blocks: 63
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 8192
Inode blocks per group: 512
Filesystem created: Fri Aug 2 15:02:13 2019
Last mount time: n/a
Last write time: Fri Aug 2 15:02:14 2019
Mount count: 0
Maximum mount count: -1
Last checked: Fri Aug 2 15:02:13 2019
Check interval: 0 (<none>)
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 256
Required extra isize: 28
Desired extra isize: 28
Default directory hash: half_md4
Directory Hash Seed: c0155456-ad7d-421f-afd1-c898746ccd76
我们需要的参数是“块大小”。
现在有趣的部分是如何读取 /home/serp/testfile 文件? 文件由一个或多个存储其数据的文件系统块组成。 知道文件名,如何找到它? 我应该阅读哪些块?
这就是 inode 派上用场的地方。 ext2fs 文件系统有一个“表”,其中包含所有 inode 的信息。 ext2fs 的 inode 数量是在创建文件系统时设置的。 我们查看tune2fs输出的“Inode count”参数中所需的数字,即我们有 65536 件。 索引节点包含我们需要的信息:我们正在查找的文件的文件系统块列表。 如何查找给定文件的索引节点号?
目录中包含相应的名称和inode号,ext2fs中的目录是一种特殊类型的文件,即也有自己的索引节点号。 为了打破这个恶性循环,根目录被分配了一个“固定”的inode编号“2”。 我们看一下2号inode的内容:
root@ubuntu:/# debugfs /dev/sdb1
debugfs 1.42.9 (4-Feb-2014)
debugfs: stat <2>
Inode: 2 Type: directory Mode: 0755 Flags: 0x0
Generation: 0 Version: 0x00000000:00000002
User: 0 Group: 0 Size: 4096
File ACL: 0 Directory ACL: 0
Links: 3 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x5d43cb51:16b61bcc -- Fri Aug 2 16:34:09 2019
atime: 0x5d43c247:b704301c -- Fri Aug 2 15:55:35 2019
mtime: 0x5d43cb51:16b61bcc -- Fri Aug 2 16:34:09 2019
crtime: 0x5d43b5c6:00000000 -- Fri Aug 2 15:02:14 2019
Size of extra inode fields: 28
BLOCKS:
(0):579
TOTAL: 1
正如您所看到的,我们需要的目录包含在块号 579 中。在其中我们将找到主文件夹的节点号,依此类推,直到在 serp 目录中我们看到所请求文件的节点号。 如果突然有人想检查号码是否正确,必要的信息是否有,这并不困难。 我们的确是:
root@ubuntu:/# dd if=/dev/sdb1 of=/home/serp/dd_image bs=4096 count=1 skip=579
1+0 records in
1+0 records out
4096 bytes (4,1 kB) copied, 0,000184088 s, 22,3 MB/s
root@ubuntu:/# hexdump -c /home/serp/dd_image
在输出中,您可以读取目录中文件的名称。
那么我就来到了主要问题:“什么原因会导致录音错误?”
当然,如果文件系统中没有剩余空闲块,就会发生这种情况。 在这种情况下可以做什么? 除了明显的“删除任何不必要的东西”之外,您应该记住,在 ext2,3、4 和 13094 文件系统中还有“保留块计数”之类的东西。 如果您查看上面的列表,我们有“XNUMX”这样的块。 这些块只能由 root 用户写入。 但如果您需要快速解决问题,作为临时解决方案,您可以将它们提供给所有人,从而产生一些可用空间:
root@ubuntu:/mnt# tune2fs -m 0 /dev/sdb1
tune2fs 1.42.9 (4-Feb-2014)
Setting reserved blocks percentage to 0% (0 blocks)
那些。 默认情况下,您有 5% 的磁盘空间不可用于写入,并且考虑到现代磁盘的容量,该空间可能达到数百 GB。
还能是什么? 也有可能存在空闲块,但没有更多节点。 如果文件系统上有一堆小于文件系统块大小的文件,通常会发生这种情况。 考虑到 1 个 inode 花费在 1 个文件或目录上,并且(对于给定的文件系统)总共有 65536 个 inode - 这种情况非常现实。 这可以从 df 命令的输出中清楚地看出:
serp@ubuntu:~$ df -hi
Filesystem Inodes IUsed IFree IUse% Mounted on
udev 493K 480 492K 1% /dev
tmpfs 493K 425 493K 1% /run
/dev/xvda1 512K 240K 273K 47% /
none 493K 2 493K 1% /sys/fs/cgroup
none 493K 2 493K 1% /run/lock
none 493K 1 493K 1% /run/shm
none 493K 2 493K 1% /run/user
/dev/xvdc1 320K 4,1K 316K 2% /var
/dev/xvdb1 64K 195 64K 1% /home
/dev/xvdh1 4,0M 3,1M 940K 78% /var/www
serp@ubuntu:~$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 2,0G 4,0K 2,0G 1% /dev
tmpfs 395M 620K 394M 1% /run
/dev/xvda1 7,8G 2,9G 4,6G 39% /
none 4,0K 0 4,0K 0% /sys/fs/cgroup
none 5,0M 0 5,0M 0% /run/lock
none 2,0G 0 2,0G 0% /run/shm
none 100M 0 100M 0% /run/user
/dev/xvdc1 4,8G 2,6G 2,0G 57% /var
/dev/xvdb1 990M 4,0M 919M 1% /home
/dev/xvdh1 63G 35G 25G 59% /var/www
从 /var/www 分区上可以清楚地看到,文件系统中的空闲块数和空闲节点数差异很大。
如果你用完了索引节点,我不会告诉你任何咒语,因为...... 没有(如果我错了,请告诉我)。 因此,对于小文件较多的分区,应该明智地选择文件系统。 例如,btrfs inode 无法结束,因为如有必要,会动态创建新的。
来源: habr.com