假设我们正在使用 ext4(启用 dir_index)来托管大约 3M 文件(平均大小为 750KB),我们需要决定要使用的文件夹方案。
在第一个解决方案中,我们对文件应用哈希函数并使用两级文件夹(第一级为 1 个字符,第二级为 2 个字符):因此filex.for
哈希等于abcde1234,我们将其存储在 /path / a/bc /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 缓存系统),如果我们选择一个或其他解决方案,它在性能意义上是否重要?
此外,我们可以使用哪些工具来检查/测试此设置?
创建这种目录结构的原因是文件系统必须在目录中定位文件,目录越大,操作越慢。
慢多少取决于文件系统设计。
ext4 文件系统使用B-tree来存储目录条目。对该表的查找预计需要O(log n)时间,大部分时间少于 ext3 和以前的文件系统使用的幼稚线性表(如果不是,则目录太小而无法使用)非常重要)。
XFS 文件系统使用B+tree代替。与哈希表或 B-tree 相比,它的优点是任何节点都可以有多个子b,其中在 XFS 中b变化并且可以高达 254(或根节点为 19;并且这些数字可能已经过时)。这为您提供了O(log b n)的时间复杂度,这是一个巨大的改进。
这些文件系统中的任何一个都可以处理单个目录中的数万个文件,在具有相同 inode 数量的目录中,XFS 比 ext4 快得多。但是您可能不想要具有 3M inode 的单个目录,因为即使使用 B+树,查找也可能需要一些时间。这就是导致首先以这种方式创建目录的原因。
至于您提出的结构,您给出的第一个选项正是 nginx 示例中显示的内容。它在任何一个文件系统上都能很好地运行,尽管 XFS 仍然有一点优势。第二个选项的性能可能稍好或稍差,但它可能非常接近,即使在基准测试中也是如此。
根据我的经验,缩放因素之一是给定哈希名称分区策略的 inode 大小。
您提出的两个选项都为每个创建的文件创建最多三个 inode 条目。此外,732 个文件将创建一个仍小于通常 16KB 的 inode。对我来说,这意味着任何一个选项都将执行相同的操作。
我为你的简短哈希鼓掌;我以前工作过的系统采用给定文件的 sha1sum 并基于该字符串拼接目录,这是一个更难的问题。
当然,对于 xfs 或 ext4 或任何文件系统,任何一个选项都有助于将目录中的文件数量减少到看起来合理的程度。哪个更好,还不清楚,要测试才能知道。
用模拟真实工作负载的应用程序进行基准测试是理想的。否则,想出一些专门模拟许多小文件的东西。说到这一点,这里有一个名为 smallfile 的开源软件。它的文档引用了其他一些工具。
hdparm
做持续的 I/O 没那么有用。它不会显示与很多文件相关的许多小 I/O 或巨大的目录条目。问题之一是扫描文件夹的方式。
想象一下对文件夹运行扫描的 Java 方法。
它必须分配大量内存并在短时间内释放它,这对 JVM 来说非常沉重。
最好的方法是按照每个文件在专用文件夹中的方式排列文件夹结构,例如年/月/日。
完成全扫描的方式是,对于每个文件夹,该函数运行一次,因此 JVM 将退出该函数,释放 RAM 并在另一个文件夹上再次运行它。
这只是一个例子,但无论如何拥有这么大的文件夹是没有意义的。
我一直有同样的问题。试图在 ext4 的 Ubuntu 服务器中存储数百万个文件。结束运行我自己的基准测试。发现平面目录的性能更好,同时使用起来更简单:
写了一篇文章。