文件夹中包含数百万个(小)文本文件

文件夹中包含数百万个(小)文本文件

我们希望在 Linux 文件系统中存储数百万个文本文件,目的是能够压缩任意集合并将其作为服务提供。我们尝试了其他解决方案,例如键/值数据库,但我们对并发性和并行性的要求使得使用本机文件系统成为最佳选择。

最直接的方法是将所有文件存储在一个文件夹中:

$ ls text_files/
1.txt
2.txt
3.txt

哪个应该可以在 EXT4 文件系统上使用,对文件夹中的文件数量没有限制。

这两个 FS 进程将是:

  1. 从网络抓取写入文本文件(不应受到文件夹中文件数量的影响)。
  2. 压缩选定的文件,由文件名列表给出。

我的问题是,在一个文件夹中存储多达一千万个文件是否会影响上述操作的性能或一般系统性能,这与为文件所在的子文件夹树创建有什么不同?

答案1

这非常接近基于意见的问题/答案,但我会尝试提供一些事实和我的意见。

  1. 如果文件夹中有大量文件,任何尝试枚举它们的基于 shell 的操作(例如mv * /somewhere/else)可能无法成功扩展通配符,或者结果可能太大而无法使用。
  2. ls枚举大量文件比枚举少量文件花费更长的时间。
  3. 文件系统将能够处理单个目录中的数百万个文件,但人们可能会遇到困难。

一项建议是将文件名拆分为两个、三个或四个字符块,并将它们用作子目录。例如,somefilename.txt可能存储为som/efi/somefilename.txt.如果您使用数字名称,则从右到左而不是从左到右拆分,以便分布更均匀。例如12345.txt可能存储为345/12/12345.txt.

您可以使用等效的zip -j zipfile.zip path1/file1 path2/file2 ...来避免在 ZIP 文件中包含中间子目录路径。

如果您从网络服务器提供这些文件(我不完全确定这是否相关),则隐藏此结构以支持 Apache2 中具有重写规则的虚拟目录是微不足道的。我认为 Nginx 也是如此。

答案2

命令ls,甚至是 shell 的 TAB 补全或通配符扩展,通常会按字母数字顺序显示结果。这需要读取整个目录列表并对其进行排序。对于单个目录中的一千万个文件,此排序操作将花费不可忽略的时间。

如果您可以抵制 TAB 补全的冲动,例如完整地写入要压缩的文件的名称,那么应该没有问题。

通配符的另一个问题可能是通配符扩展可能会产生比最大长度命令行容纳的文件名更多的文件名。典型的最大命令行长度对于大多数情况来说已经足够了,但是当我们谈论单个目录中的数百万个文件时,这不再是一个安全的假设。当通配符扩展超过最大命令行长度时,大多数 shell 只会使整个命令行失败而不执行它。

这可以通过使用以下命令执行通配符操作来解决find

find <directory> -name '<wildcard expression>' -exec <command> {} \+

或尽可能使用类似的语法。将find ... -exec ... \+自动考虑最大命令行长度,并根据需要多次执行命令,同时将最大数量的文件名适合每个命令行。

答案3

我经营一个网站,处理电影、电视和视频游戏的数据库。对于其中每一个,电视都有多个图像,每个节目包含数十个图像(即剧集快照等)。

最终会产生很多图像文件。在 250,000+ 范围内。这些都存储在访问时间合理的已安装块存储设备中。

我第一次尝试存储图像是在一个文件夹中/mnt/images/UUID.jpg

我遇到了以下挑战。

  • ls通过远程终端就会挂起。该过程将变得僵化并且CTRL+C不会破坏它。
  • 在我到达该点之前,任何ls命令都会快速填充输出缓冲区,并且CTRL+C不会停止无休止的滚动。
  • 从一个文件夹中压缩 250,000 个文件大约需要 2 小时。您必须运行与终端分离的 zip 命令,否则任何连接中断都意味着您必须重新开始。
  • 我不会冒险尝试在 Windows 上使用 zip 文件。
  • 该文件夹很快就变成了没有人类允许区。

我最终不得不使用创建时间来创建路径,将文件存储在子文件夹中。例如/mnt/images/YYYY/MM/DD/UUID.jpg。这解决了上述所有问题,并允许我创建针对日期的 zip 文件。

如果您拥有的文件的唯一标识符是数字,并且这些数字往往按顺序运行。为什么不按100000,10000和 来对它们进行分组1000

例如,如果您有一个名为384295.txt路径的文件:

/mnt/file/300000/80000/4000/295.txt

如果你知道的话你会达到几百万。使用01,000,000 个前缀

/mnt/file/000000/300000/80000/4000/295.txt

答案4

从网络抓取写入文本文件(不应受到文件夹中文件数量的影响)。

要创建新文件,需要扫描目录文件,为新目录条目寻找足够的空白空间。如果没有足够大的空间来存储新的目录条目,它将被放置在目录文件的末尾。随着目录中文件数量的增加,扫描目录的时间也会增加。

只要目录文件保留在系统缓存中,这样对性能的影响就不会很差,但如果数据被释放,从磁盘读取目录文件(通常是碎片化的)可能会消耗相当多的时间。 SSD 改善了这一点,但对于包含数百万个文件的目录,仍然可能会出现明显的性能影响。

压缩选定的文件,由文件名列表给出。

这也可能需要在包含数百万个文件的目录中花费额外的时间。在具有散列目录条目的文件系统(如 EXT4)中,这种差异很小。

在一个文件夹中存储多达一千万个文件是否会影响上述操作的性能或一般系统性能,这与为文件所在的子文件夹树创建有什么不同?

子文件夹树不存在上述性能缺陷。此外,如果底层文件系统更改为没有散列文件名,树方法仍然可以很好地工作。

相关内容