我们希望在 Linux 文件系统中存储数百万个文本文件,目的是能够压缩并将任意集合作为服务提供。我们尝试了其他解决方案,例如键/值数据库,但我们对并发性和并行性的要求使得使用本机文件系统成为最佳选择。
最直接的方法是将所有文件存储在一个文件夹中:
$ ls text_files/
1.txt
2.txt
3.txt
这在 EXT4 文件系统上应该是可能的,它对文件夹中的文件数量没有限制。
两个 FS 进程将是:
- 从网络抓取中写入文本文件(不受文件夹中文件数量的影响)。
- 压缩选定的文件,由文件名列表给出。
我的问题是,在文件夹中存储多达一千万个文件会影响上述操作的性能或一般系统性能,这与为文件创建子文件夹树有什么不同吗?
这非常接近基于意见的问题/答案,但我会尝试提供一些事实和我的意见。
mv * /somewhere/else
)都可能无法成功扩展通配符,或者结果可能太大而无法使用。ls
枚举大量文件比枚举少量文件需要更长的时间。一种建议是将文件名分成两个、三个或四个字符块,并将它们用作子目录。例如,
somefilename.txt
可能存储为som/efi/somefilename.txt
. 如果您使用数字名称,则从右到左而不是从左到右拆分,以便分布更均匀。例如12345.txt
可能存储为345/12/12345.txt
.您可以使用等效项
zip -j zipfile.zip path1/file1 path2/file2 ...
来避免在 ZIP 文件中包含中间子目录路径。如果您从网络服务器提供这些文件(我不完全确定这是否相关),隐藏此结构以支持在 Apache2 中具有重写规则的虚拟目录是微不足道的。我认为 Nginx 也是如此。
ls
命令,甚至是 shell 的 TAB 补全或通配符扩展,通常会以字母数字顺序显示它们的结果。这需要阅读整个目录列表并对其进行排序。在单个目录中有一千万个文件,此排序操作将花费不可忽略的时间。如果你能抵制制表符完成的冲动,例如写下要压缩的文件名,应该没有问题。
通配符的另一个问题可能是通配符扩展可能会产生比最大长度命令行更多的文件名。对于大多数情况,典型的最大命令行长度绰绰有余,但是当我们谈论单个目录中的数百万个文件时,这不再是一个安全的假设。当通配符扩展中超过最大命令行长度时,大多数 shell 将简单地使整个命令行失败而不执行它。
这可以通过使用以下
find
命令执行通配符操作来解决:或尽可能使用类似的语法。将
find ... -exec ... \+
自动考虑最大命令行长度,并根据需要多次执行命令,同时为每个命令行拟合最大数量的文件名。我经营一个网站,该网站处理电影、电视和视频游戏的数据库。对于其中的每一个,电视都有多个图像,每个节目包含数十个图像(即剧集快照等)。
最终会有很多图像文件。在 250,000+ 范围内的某个地方。这些都存储在访问时间合理的已安装块存储设备中。
我第一次尝试存储图像是在一个文件夹中
/mnt/images/UUID.jpg
我遇到了以下挑战。
ls
通过远程终端只会挂起。该过程将变成僵尸并且CTRL+C
不会破坏它。ls
命令都会快速填充输出缓冲区并且CTRL+C
不会停止无休止的滚动。我最终不得不使用创建时间将文件存储在子文件夹中来创建路径。比如
/mnt/images/YYYY/MM/DD/UUID.jpg
。这解决了上述所有问题,并允许我创建以日期为目标的 zip 文件。如果您拥有的文件的唯一标识符是数字,并且这些数字往往按顺序运行。为什么不按 和 对它们
100000
进行10000
分组1000
。例如,如果您有一个名为
384295.txt
路径的文件,则为:如果你知道你会达到几百万。使用
0
1,000,000 的前缀首先:防止 'ls' 使用 'ls -U' 进行排序,也许更新你的 ~/bashrc 以具有 'alias ls="ls -U"' 或类似的。
对于您的大型文件集,您可以这样尝试:
创建一组测试文件
查看是否有许多文件名导致问题
使用 xargs 参数批处理和 zip 的(默认)将文件添加到 zip 的行为以避免出现问题。
这很好用:
要创建新文件,需要扫描目录文件,为新目录条目寻找足够的空白空间。如果没有找到足够大的空间来存储新的目录条目,它将被放置在目录文件的末尾。随着目录中文件数量的增加,扫描目录的时间也会增加。
只要目录文件保留在系统缓存中,这样做对性能的影响不会很差,但是如果数据被释放,从磁盘读取目录文件(通常是高度碎片化的)可能会消耗相当多的时间。SSD 改善了这一点,但对于包含数百万个文件的目录,仍然可能会对性能造成明显影响。
在包含数百万个文件的目录中,这也可能需要额外的时间。在具有散列目录条目的文件系统(如 EXT4)中,这种差异很小。
子文件夹树没有上述性能缺陷。此外,如果将底层文件系统更改为没有散列文件名,树方法仍然可以正常工作。