最快的文件访问/存储方式?

8
我大约有7.5亿个文件需要存储在磁盘上。更重要的是,我需要在尽可能 最短的时间内 随机访问这些文件--随时访问任何给定的文件。我需要做什么来使访问这些文件最快?
将它们组织成类似散列表的方式,哈希键是文件名,关联值是文件的数据。
一位同事建议将它们组织成这样的目录结构:如果我想要存储一个名为“foobar.txt”的文件,并且它存储在D盘上,则将文件放在“D:\f\o\o\b\a\r.\t\x\t”中。然而,他无法解释为什么这是一个好主意。这个想法有什么用吗?
有什么好的想法吗? 关键是找到一个文件。以最快的方式查找文件名并打开它? 编辑:
  • 我无法控制存储此数据的文件系统。它将使用NTFS或FAT32。
  • 文件数据存储在数据库中不可行。
  • 文件将非常小——最多可能1kb。
  • 驱动器将是固态的。
  • 数据访问几乎是随机的,但我可能可以根据请求频率为每个文件确定优先级。某些文件的访问次数要多得多。
  • 项目将不断添加,有时会删除。
  • 将多个文件合并为单个文件是不切实际的,因为文件之间没有逻辑关联。
  • 我很想通过对这些内容进行测试来收集一些指标,但这可能会像项目本身一样消耗大量时间!

  • 这些数据是静态的(750百万),还是你会定期添加新的文件?它只需要读取,还是你也需要更新文件?它是真正的随机文件访问,或者在近距离观察时可以发现任何访问模式吗? - Scanningcrew
    更新问题以回答此问题。(定期添加更多文件,文件删除不太频繁。访问是随机的,但有些文件将比其他文件更常被访问。) - JamesBrownIsDead
    关于您的EDIT2评论,您只需要15个声望即可投票支持。请参阅http://stackoverflow.com/faq了解详情。 - Greg Hewgill
    10个回答

    2
    这似乎主要与文件系统的选择有关。一个值得考虑的选项可能是ZFS,它专为高容量应用而设计。
    您可能还想考虑使用关系型数据库来处理这种情况。750万行算是中等规模的数据库,因此任何强大的DBMS(例如PostgreSQL)都能很好地处理它。您也可以在数据库中存储任意的blob数据,因此您原本要在磁盘上存储的内容可以直接存储在数据库中。 更新:您提供的额外信息确实很有帮助。在FAT32和NTFS之间进行选择时,一定要选择NTFS。不要在单个目录中存储过多的文件,100,000个文件可能是一个上限(尽管您将不得不进行实验,因为没有硬性规定)。您朋友的建议每个字母新建一个目录可能太多了,您可以考虑每四个字母分割一次。最佳值的选择取决于您数据集的形状。
    分割名称的原因是通常文件系统的性能会随着目录中文件数的增加而降低。这高度依赖于所使用的文件系统,例如FAT32将在每个目录中只有几千个文件时就会变得非常糟糕。您不希望将文件名分割得太多,因此可以最小化文件系统需要进行的目录查找次数。

    数据库方案会很好用,但可能不够快。在没有进行测试之前,我会非常谨慎地猜测。通过数据库索引查找文件意味着使用搜索树。基于目录的trie实现的建议解决方案也允许通过树进行O(log n)访问,但按字母分割意味着您没有太多控制节点如何分裂。文件名中的模式可能导致巨大的节点。 - J. Loomis
    没错,我不会试图声称数据库更快,但它是另一个应该考虑的选项。然而,数据库被设计用于处理具有任意病态模式的字符串类型键。 :) - Greg Hewgill

    2
    那个文件算法可以工作,但不是最优的。我认为使用2或3个字符的“段”会更好,特别是当你开始考虑备份时。
    例如:
    d:\ storage \ fo \ ob \ ar \ foobar.txt
    或者
    d:\ storage \ foo \ bar \ foobar.txt
    使用这种算法有一些好处:
    1. 不需要访问数据库。
    2. 文件将分布在许多目录中。如果您不将它们分散开来,您将遇到严重的性能问题。(我模糊地听说过有人在单个文件夹中拥有约40,000个文件的问题,但我对该数字不太自信。)
    3. 不需要搜索文件。您可以从文件名确定文件的确切位置。
    4. 简单性。您可以非常轻松地将此算法移植到任何语言。
    这也有一些缺点:
    1. 许多目录可能导致备份变慢。想象一下对这些目录进行递归差异。
    2. 可扩展性。当您用尽磁盘空间并需要添加更多存储时会发生什么?
    3. 您的文件名不能包含空格。

    1

    这高度取决于许多因素:

    • 您使用的文件系统是什么?
    • 每个文件有多大?
    • 您使用的驱动器类型是什么?
    • 访问模式是什么?

    在传统磁盘上纯粹随机访问文件确实非常昂贵。您可以获得的一个重要改进是使用固态硬盘。

    如果您能理解访问模式,您可能能够利用引用局部性来放置这些文件。

    另一种可能的方法是使用数据库系统,并将这些文件存储在数据库中以利用系统的缓存机制。

    更新:

    根据您的更新,您是否可以合并一些文件?1k 文件不太适合存储为文件系统(fat32、ntfs)具有簇大小,即使文件小于簇大小,每个文件也将使用簇大小。通常每个文件夹中的文件数都有限制,会影响性能。您可以通过将尽可能多的 10k 文件放入一个文件夹中来进行简单的基准测试,以查看性能下降了多少。

    如果您打算使用 trie 结构,我建议调查文件名的分布,然后根据分布将它们分成不同的文件夹。


    1

    这在很大程度上取决于您将要存储文件的文件系统。文件系统处理大量文件的能力差异很大。

    您的同事基本上建议使用Trie数据结构。使用这样的目录结构意味着在每个目录级别上只有少数文件/目录可供选择;这可能有所帮助,因为随着目录中文件数量的增加,访问其中一个文件的时间也会增加(实际时间差异取决于文件系统类型)。

    话虽如此,我个人不会深入那么多层次——三到四个层次应该足以提供性能优势——之后的大多数层次可能都只有很少的条目(假设您的文件名没有遵循任何特定的模式)。

    此外,我会将文件本身与其完整名称一起存储,这将使手动遍历此目录结构变得更容易,如果需要的话。

    因此,我会将foobar.txt存储为f/o/o/b/foobar.txt


    1
    首先,该文件的大小非常小。任何文件系统都会占用至少4倍的空间。我指的是磁盘上的任何文件都将占用1KB文件的4KB。特别是在SSD硬盘上,4KB扇区将成为标准。
    因此,您必须将多个文件分组到一个物理文件中。在一个存储文件中放置1024个文件似乎是合理的。要定位这些存储文件中的单个文件,您必须使用一些RDBMS(提到了PostgreSQL它很好,但SQLite可能更适合)或类似的结构来进行映射。
    您朋友建议的目录结构听起来不错,但它并没有解决物理存储问题。您可以使用类似的目录结构来存储存储文件。最好使用数字系统对其进行命名。
    如果可以,请勿将其格式化为FAT32,至少使用NTFS或某些最近的Unix文件系统。由于文件的总大小并不大,因此NTFS可能已经足够了,但ZFS是更好的选择...

    0

    个别文件之间有关联吗?就访问时间而言,你把东西放在哪个文件夹里并不会影响太多;物理位置才是重要的。


    0
    为什么将路径存储在数据库表中不可接受?

    0

    我猜他在考虑使用Trie数据结构在磁盘上创建节点为目录的方式。


    0

    0

    我知道现在已经晚了几年,但也许这可以帮助下一个人。

    我的建议是使用 SAN,并映射到其他服务器也可以映射的 Z 驱动器。我不会选择你朋友所说的文件夹路径,而是采用 drive:\clientid\year\month\day\ 的方式,如果每天摄入超过 10 万个文档,则可以根据需要添加小时甚至分钟的子文件夹。这样,您永远不会有超过 60 个子文件夹,同时可以一直到秒。将链接存储在 SQL 中以便快速检索和报告。这使得文件夹路径非常简短,例如:Z:\05\2004\02\26\09\55\filename.txt,因此您不会在全局范围内遇到 256 个限制。

    希望能对某些人有所帮助。:)


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接