【问题标题】:Best way to store many files in disk在磁盘中存储许多文件的最佳方法
【发布时间】:2010-02-09 14:51:56
【问题描述】:

我找不到问题的好标题,这就是我想要做的:

  • 这是 .NET 应用程序。
  • 我需要存储多达 200000 个对象(3KB-500KB 之间)
  • 我需要每秒从多线程中存储大约 10 个
  • 我在存储之前使用二进制序列化
  • 稍后我需要通过一个唯一的整数 ID 访问它们

最好的方法是什么?

  • 我无法将它们保留在内存中,因为我会遇到内存不足异常
  • 当我将它们作为单独的文件存储在磁盘中时,可能会出现哪些性能问题?它会大大降低整体性能吗?
  • 我是否应该实现某种缓存,例如组合 100 个对象并将其作为一个文件写入一次。然后稍后解析它们。或者类似的东西?
  • 应该使用数据库吗? (访问时间并不重要,不会有搜索,我只会通过已知的唯一 ID 访问几次)。理论上我不需要数据库,我不想让这个复杂化。

更新:

  • 我认为数据库会比文件系统慢,如果您对此有所了解,请证明我错了。所以这就是为什么我也倾向于文件系统。但我真正担心的是每秒将 200KB*10 写入 HDD(这可以是任何 HDD,我不控制硬件,它是一个桌面工具,将部署在不同的系统中) .
  • 如果我使用文件系统,我会将文件存储在单独的文件夹中以避免与文件系统相关的问题(因此您可以忽略该限制

【问题讨论】:

  • 唯一ID是提供给我们的,还是我们必须自己生成?如果我们必须生成它,它是否需要在系统重启后仍然存在?
  • unique id 已经被提供,它不需要在重启后存活。它只是在应用程序运行期间需要。
  • 注意骗局,但请参阅:stackoverflow.com/questions/2230032/…
  • 你会编辑或删除记录吗?
  • @Albin 在用户完成该过程后从不编辑而是删除所有记录。

标签: .net performance memory storage


【解决方案1】:

如果您想避免使用数据库,您可以将它们作为文件存储在磁盘上(为了简单起见)。但是在单个目录中维护大量文件时,您需要注意文件系统注意事项。

许多常见的文件系统在某种顺序列表中维护每个目录的文件(例如,简单地将文件指针或 inode 一个接一个地存储,或者存储在链表中。)这使得打开位于底部的文件列表真的很慢。

一个好的解决方案是将您的目录限制为少数节点(例如 n = 1000),并在目录下创建一个文件树。

所以不要将文件存储为:

/dir/file1 /dir/file2 /dir/file3 ... /dir/fileN

将它们存储为:

/dir/r1/s2/file1 /dir/r1/s2/file2 ... /dir/rM/sN/fileP

通过这种方式拆分文件,您可以显着缩短大多数文件系统的访问时间。

(请注意,有一些新的文件系统表示树中的节点或其他形式的索引。这种技术也适用于这些。)

其他考虑因素是调整文件系统(块大小、分区等)和缓冲区缓存,以便获得良好的数据局部性。根据您的操作系统和文件系统,有很多方法可以做到这一点 - 您可能需要查找它们。

或者,如果这不能解决问题,您可以使用某种嵌入式数据库,如 SQLlite 或 Firebird。

HTH。

【讨论】:

  • 我不控制硬件,所以它可以是任何东西,从带有 FAT32 的蹩脚 HDD(不太可能但可能)到 RAID。操作系统始终是 Windows,尽管这是 Windows 中的 .NET,没有单声道的东西。
  • @dr.邪恶:我认为如果“糟糕的硬盘”无法存储 2MB/秒,任何解决方案(包括 DMBS)都会失败,因为任何 DBMS 在存储数据时都会增加自己的开销。
  • 这是个糟糕的主意;我试过这样的东西,即使在像 ext4 这样的现代文件系统中也是不切实际的。如果您将更多的感谢 8k 文件放在 8k 目录中,大多数 FS 都会窒息。我的设置对每个文件进行了哈希处理并将其放入像 img/a412/8cdf/e9k4/rest_of_hash.png 这样的目录结构中,它基本上杀死了我,因为我 (a) 用完了 inode,(b) 由于数千个文件拖网而杀死了所有文件目录和 (c) 使用了大量额外的磁盘空间,因为每个目录都是 4096k,即使我的图像是 2k。像这样的文件系统存储对于大规模解决方案来说是一个坏主意。
【解决方案2】:

我很想在 C++ 中使用 sqlite 或 coucheDB 中的数据库。
这些都可以在 .Net 中使用,但我不知道是否有更好的 .Net 特定替代方案。

即使在可以处理目录中 200,000 个文件的文件系统上,打开目录也需要永远

编辑 - 数据库可能会更快!
文件系统不是为大量小对象而设计的,数据库是。
它将实现您从未想过的各种巧妙的缓存/事务策略。

有些照片网站选择文件系统而不是数据库。但他们主要是读取相当大的 blob,并且他们有很多管理员专门针对此特定应用程序调整服务器。

【讨论】:

  • 任何数据库都有性能优势吗?我假设它会更慢,如果有的话,文件系统有什么优势(假设我将文件系统中的每个文件夹分组 1000 个文件 - 这很容易解决打开目录问题)。
【解决方案3】:

我建议创建一个具有单线程队列的类,用于将图像(gzipped)转储到文件末尾,然后将文件偏移量/元信息保存到像 sqlite 这样的小型数据库中。这使您可以从多个线程快速、紧密地存储所有文件,并高效地读回它们,而无需处理任何文件系统怪癖(除了最大文件大小——这可以通过一些额外的元数据来处理。

File:
file.1.gzipack

Table:
compressed_files {
  id,
  storage_file_id,
  storage_offset,
  storage_compressed_length,
  mime_type,
  original_file_name
}

【讨论】:

    【解决方案4】:

    您可以查看mongoDb,它支持存储文件。

    【讨论】:

    • MongoDB有什么性能优势吗?我认为它会更慢,如果它比文件系统有什么优势(假设我将文件系统中的每个文件夹分组 1000 个文件)
    【解决方案5】:

    确定的唯一方法是更多地了解您的使用场景。

    例如,以后使用文件是否需要一次包含 100 个文件的集群?也许如果这样做的话,将它们结合起来是有意义的。

    在任何情况下,我都会尝试从一开始就制定一个简单的解决方案,并且仅在您以后发现自己有性能问题时才更改它。

    我会这样做:

    1. 创建一个处理存储和检索的类(以便您以后可以更改该类,而不是应用程序中使用它的每个点)
    2. 将文件按原样存储在磁盘上,不要合并它们
    3. 将它们分散到子目录中,每个目录中保留 1000 个或更少的文件(如果单个目录中有许多文件,则目录访问会增加开销)

    【讨论】:

    • 使用场景如题中解释清楚,后面的使用根本不重要,我只会访问0-10次,需要通过ID访问。只要在 15-30 秒以下,多长时间并不重要。
    【解决方案6】:

    我实际上不使用 .NET,所以我不确定那里有什么简单的,但总的来说我会提供两条建议。

    如果您需要大量写入而很少阅读(例如日志文件),您应该创建一个 .zip 文件或类似文件(选择不会过多降低性能的压缩级别;在 1-9 等级, 5 左右通常对我有用)。这给您带来了几个优势:您不会对文件系统造成太大影响,减少了存储空间,并且您可以自然地将文件分组为 100 或 1000 或其他块。

    如果您需要大量写入大量阅读,您可以定义自己的平面文件格式(除非您可以访问实用程序来读取和写入 .tar 文件等,或者作弊并将二进制数据放入 8 位灰度 TIFF 中)。为每个标头定义记录——可能每个 1024 字节,其中包含文件的偏移量和文件名以及您需要存储的任何其他内容——然后以块的形式写入数据。当你需要读取一个chunk时,你首先读取header(可能是100k)然后跳转到你需要的offset,读取你需要的数量。固定大小标头的优点是您可以在开始时向它们写入空数据,然后在文件末尾继续追加新内容,然后返回并覆盖相应的记录。

    最后,您可能会研究 HDF5 之类的东西;我不知道 .NET 对此的支持是什么,但它是存储通用数据的好方法。

    【讨论】:

      【解决方案7】:

      您可以考虑使用 Microsoft 的缓存应用程序块。您可以将其配置为使用 IsolatedStorage 作为后备存储,因此缓存中的项目将被序列化到磁盘。性能可能是个问题 - 我认为它开箱即用会阻止写入,因此您可能需要对其进行调整以改为执行异步写入。

      【讨论】:

        【解决方案8】:

        在您的情况下,memchached 可能会解决一些性能问题。

        【讨论】:

          猜你喜欢
          • 2022-01-06
          • 2011-03-23
          • 2022-06-10
          • 2019-11-04
          • 1970-01-01
          • 2011-06-15
          • 2021-04-07
          • 1970-01-01
          • 2021-06-19
          相关资源
          最近更新 更多