我管理一个包含文件存储的应用程序,其中存储的所有文件的文件名都等于其 md5 总和。所有文件都存储在一个目录中。目前服务器上有数千个文件,但很快就会有数百万个文件。当前服务器在 ext4 文件系统上运行 Ubuntu 11.10。
有人告诉我,将许多文件放在一个目录中是不明智的,因为这会显著增加查找时间和可靠性(他讲了一个故事,一个目录可以指向的最大文件数,导致链接列表很大)。相反,他建议创建子目录,例如文件名的子字符串。然而,这会让我的应用程序中的一些事情变得更加繁琐。
这仍然是正确的吗,或者现代文件系统(例如 ext4)是否有更有效的方法来处理这个问题并自然扩展?维基百科有一些关于文件系统的详细信息,但实际上并没有提到每个目录的最大文件数或查找时间。
答案1
这ext3
支持散列 B 树目录索引。只要您执行的操作只是添加、删除和按名称访问,这种方法的扩展性就很好。但是,我仍然建议将目录拆分。否则,您会为执行目录其他操作的工具(updatedb
、ls
、du
等)创建一个危险的陷阱,如果目录中的条目太多,这些工具可能会崩溃。
答案2
问题的核心是挖掘目录 inode 以找到所需的文件。有些文件系统比其他文件系统做得更好。有些文件系统的规模接近数十亿,但如果你只有……20K 个文件到达处理这些文件的速度明显更快。此外,文件数量过多也会给某些工具带来问题,并可能使备份/恢复变得更加困难。
碰巧的是,我在我们自己的开发中遇到了完全相同的问题(md5sum 作为文件名,并对其进行缩放)。我建议我们的开发人员将字符串分成几部分。他们选择了 4 个一组,但在我们当时使用的文件系统上,从性能角度来看,即使是这么多也会有问题,所以他们最终将前 6 个三元组分成 3 个一组,其余的则保留为终端目录中的文件名。
4 人组:4976/d70b/180c/6142/c617/d0c8/9d0b/bd2b.txt
3 人组:497/6d7/0b1/80c/614/2c6/17d0c89d0bbd2b.txt
这样做的好处是可以保持目录大小较小,而且由于 MD5sum 非常随机,因此它会创建平衡的目录树。最后一个目录不太可能包含超过几个文件。而且在我们的代码中实现起来并不难。我们处理数百万个文件的项目,因此扩展对我们来说非常重要。
答案3
现代文件系统可以很好地处理非常大的目录,甚至数百万个文件。但传统工具却不能。例如,使用“ls”列出如此大的目录将需要相当长的时间,因为它通常会读取整个目录并对其进行排序(尽管您可以使用 ls -f 来避免排序)。它不会开始显示文件,直到所有文件都读取完毕。拆分名称在某些情况下会有所帮助,但并非在所有情况下都有所帮助(例如,rsync 复制可能仍需要收集整个名称树)。
答案4
我可以建议改用 SQL 数据库吗?这可能会将应用程序中的这一明显弱点转化为优势。