超慢的 Ext4 目录遍历

超慢的 Ext4 目录遍历

我目前正在开发一个系统,该系统将文件存储在大磁盘(10 TiB 和 16 TiB)的 EXT4 分区中。所有磁盘都通过 SATA 连接到 HBA(Dell PERC H310)。

文件结构如下:/mnt/diskN/nXXX/store/some_id/twoletters/random_name文件大小各不相同,从几KiB到几MiB。

可以想象,一个 500 GiB 的/mnt/diskN/nXXX文件夹里总共有大约 150 万个文件,它们位于不同的子文件夹中。每个/mnt/diskN/nXXX/store/some_id/twoletters/文件夹可以包含数百个小文件。

我的问题是,我发现在纸面上具有相同规格的磁盘之间执行目录遍历的性能非常不同,在某些情况下甚至是相同的型号。

为了衡量我的性能,我du对每个都进行了测试/mnt/diskN/,发现大约相同使用空间的磁盘之间的性能提高了 100 倍。

到目前为止我已经检查了一些事情:

  • dir_index在所有情况下都已启用 Ext4 。
  • 所有磁盘都安装有defaults,noatime
  • e2fsck -fyvD在所有磁盘上执行以优化目录。
  • Ext4 保留块约为 50 GiB 的空间,用于进行碎片整理。
  • 不连续的文件约为3.7%。

tune2fs 输出的示例:

tune2fs 1.46.5 (30-Dec-2021)
Filesystem volume name:   disk2
Last mounted on:          /app/storage
Filesystem UUID:          edc25fd5-48c9-48cc-86f9-115fe9fe1d2b
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index fast_commit filetype needs_recovery extent 64bit flex_bg large_dir sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              305201152
Block count:              2441609203
Reserved block count:     13107200
Overhead clusters:        19533367
Free blocks:              1584334746
Free inodes:              294994216
First block:              0
Block size:               4096
Fragment size:            4096
Group descriptor size:    64
Reserved GDT blocks:      883
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         4096
Inode blocks per group:   256
Flex block group size:    16
Filesystem created:       Sun Mar 27 16:55:23 2022
Last mount time:          Tue Jul 26 20:30:38 2022
Last write time:          Tue Jul 26 20:31:37 2022
Mount count:              2
Maximum mount count:      -1
Last checked:             Tue Jul 26 20:13:48 2022
Check interval:           0 (<none>)
Lifetime writes:          9 TB
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
First orphan inode:       17367446
Default directory hash:   half_md4
Directory Hash Seed:      c98a7272-eddd-4bd8-aac4-dfe714d4cc48
Journal backup:           inode blocks
Checksum type:            crc32c
Checksum:                 0xfd641daa

我所看到的两个磁盘之间的唯一区别是,根据tune2fs -l统计数据,其中一个磁盘写入了约 9 TB,而另一个磁盘仅写入了约 2 TB(但是,当前使用的空间是相同的)。

有什么想法可以改善这种情况吗?我可以停用任何 Ext4 功能来提高此用例的性能吗?

更新

我刚刚找到了这些信息:

    14135350 inodes used (2.89%, out of 488308736)
      436787 non-contiguous files (0.1%)
       24565 non-contiguous directories (0.2%)
             # of inodes with ind/dind/tind blocks: 0/0/0
             Extent depth histogram: 14119456/15886
   978816885 blocks used (25.06%, out of 3906469627)
           0 bad blocks
           1 large file

    14077331 regular files
       58010 directories
           0 character device files
           0 block device files
           0 fifos
           0 links
           0 symbolic links (0 fast symbolic links)
           0 sockets

实际现有目录中约有 50% 是不连续的。这可能是性能缓慢的原因吗?我该如何修复它?

答案1

请参阅我发布的答案这里。正如我在那里写的,问题在于 readdir() 和 stat() 的组合,因为在硬盘上,不在 inode 缓存中的文件的每个 stat(2)(在最坏的情况下)都会导致随机 4k 读取。在硬盘上,如果您有数千或数百万个文件,这些随机读取就会累积起来。对于大多数文件系统来说,情况都是如此。

按 inode 编号顺序对文件进行排序可能会有所帮助,但最终,优化此类工作负载的最佳方法是尽可能避免 stat(2) 系统调用。如果您尝试存储大量小块,那么具有适当索引的数据库可能是您的应用程序的更好选择。

答案2

看起来问题的根源是文件夹的数量和文件碎片。

e2fsck返回files non-contiguous上面显示的磁盘上碎片的~0.1%(),但这是总可用inode的百分比。

如果我查看文件碎片的百分比,它会返回 3.09%,其中 42.11% 的文件夹碎片。

在最糟糕的情况下,13.25%的文件碎片化,35.71%的文件夹碎片化。

我不确定目录碎片的根本原因以及如何避免它,但我将针对此提出一个单独的问题。

相关内容