现代文件系统中数百万个文件的性能有何影响?

现代文件系统中数百万个文件的性能有何影响?

假设我们使用 ext4(启用了 dir_index)来托管大约 3M 个文件(平均大小为 750KB),我们需要决定要使用哪种文件夹方案。

在里面第一个解决方案,我们对文件应用哈希函数并使用两级文件夹(第一级为 1 个字符,第二级为 2 个字符):因此哈希filex.for等于abcde1234,我们将其存储在 /path/一/公元前/abcde1234-filex.for.

在里面第二种解决方案,我们对文件应用哈希函数并使用两级文件夹(第一级为 2 个字符,第二级为 2 个字符):因此哈希filex.for等于abcde1234,我们将其存储在 /path/ab/de/abcde1234-filex.for.

对于第一个解决方案,我们将采用以下/path/[16 folders]/[256 folders]方案每个文件夹平均有 732 个文件(最后一个文件夹,文件将驻留在该文件夹中)。

而在第二个解决方案中,我们将/path/[256 folders]/[256 folders]使用每个文件夹平均有 45 个文件

考虑到我们要写入/取消链接/读取文件(但大多是阅读)从这个方案中得到了很多(基本上是 nginx 缓存系统),从性能角度来看,选择一种或另一种解决方案是否重要?

另外,我们可以使用哪些工具来检查/测试此设置?

答案1

创建这种目录结构的原因是文件系统必须在目录中定位文件,并且目录越大,操作越慢。

具体慢多少取决于文件系统的设计。

ext4 文件系统使用B 树存储目录条目。查找此表预计需要O(log n)时间,大多数时候它比 ext3 和以前的文件系统使用的简单线性表要短(如果不是,则目录太小,因此无关紧要)。

XFS 文件系统使用B+树相反。与哈希表或 B 树相比,它的优点是任何节点都可以有多个子节点b,在 XFS 中b变化,最高可达 254(对于根节点,则为 19;这些数字可能已过时)。这为您提供了时间复杂度O(log b n),一个巨大的进步。

这两种文件系统都可以处理单个目录中的数万个文件,在拥有相同数量 inode 的目录中,XFS 的速度明显快于 ext4。但您可能不希望单个目录拥有 3M 个 inode,因为即使使用 B+tree,查找也需要一些时间。这就是以这种方式创建目录的初衷。

至于您提议的结构,您给出的第一个选项正是 nginx 示例中所展示的。它在任一文件系统上都表现良好,尽管 XFS 仍会略有优势。第二个选项的表现可能略好或略差,但即使在基准测试中也可能非常接近。

答案2

根据我的经验,缩放因素之一是给定哈希名称分区策略的 inode 的大小。

您提出的两个选项都为每个创建的文件创建最多三个 inode 条目。此外,732 个文件将创建一个小于通常的 16KB 的 inode。对我来说,这意味着两个选项的效果都一样。

我为你的简短哈希鼓掌;我以前研究过的系统已经获取了给定文件的 sha1sum 并根据该字符串拼接目录,这是一个更难的问题。

答案3

当然,对于 xfs 或 ext4 或任何文件系统,这两种方法都有助于将目录中的文件数量减少到合理的水平。尚不清楚哪种方法更好,必须进行测试才能知道。

使用应用程序模拟真实工作负载是理想的选择。否则,想出一个专门模拟许多小文件的方法。说到这个,这是一个名为 smallfile 的开源程序. 其文档引用了一些其他工具。

hdparm持续 I/O 没那么有用。它不会显示与很多文件相关的许多小 I/O 或巨大目录条目。

答案4

其中一个问题是扫描文件夹的方式。

想象一下对文件夹运行扫描的 Java 方法。

它将不得不分配大量内存并在短时间内释放它,这对 JVM 来说非常沉重。

最好的方法是按照每个文件位于专用文件夹中的方式安排文件夹结构,例如年/月/日。

完成全面扫描的方式是,对于每个文件夹,都会运行一次该函数,因此 JVM 将退出该函数,释放 RAM 并在另一个文件夹上再次运行它。

这只是一个例子,但无论如何,拥有这么大的文件夹是没有意义的。

相关内容