将许多文件存储在磁盘中的最佳方法

时间:2010-02-09 14:51:56

标签: .net performance memory storage

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

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

最好的方法是什么?

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

更新

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

8 个答案:

答案 0 :(得分:3)

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

许多常见的文件系统在某种顺序列表中维护每个目录的文件(例如,简单地一个接一个地存储文件指针或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。

答案 1 :(得分:2)

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

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

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

有照片网站通过数据库选择文件系统。但他们主要是在相当大的blob上进行读取,他们有很多管理员专门为这个特定的应用程序调整他们的服务器。

答案 2 :(得分:2)

我建议创建一个具有单线程队列的类,用于将图像(gzip)转储到文件末尾,然后将文件offsets / meta-info保存到像sqlite这样的小型数据库中。这允许您从多个线程快速,紧密地存储所有文件,并有效地读取它们,而无需处理任何文件系统怪癖(除了max filesize之外 - 可以通过添加一些额外的元数据来处理)。

File:
file.1.gzipack

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

答案 3 :(得分:1)

您可以查看mongoDb,它支持商店文件。

答案 4 :(得分:0)

确定的唯一方法是了解有关您的使用方案的更多信息。

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

在任何情况下,我都会尝试制作一个简单的解决方案,并且只有在您稍后发现存在性能问题时才进行更改。

这就是我要做的事情:

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

答案 5 :(得分:0)

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

如果你需要写很多并且很少阅读(例如日志文件),你应该创建一个.zip文件等(选择一个不会太慢降低性能的压缩级别;在1-9级别中) ,5左右通常适合我)。这给您带来了几个好处:您不会如此努力地访问文件系统,减少存储空间,并且您可以自然地将文件分组为100或1000或其他任何块。

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

最后,你可能会看到像HDF5这样的东西;我不知道.NET对它的支持是什么,但它是存储通用数据的好方法。

答案 6 :(得分:0)

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

答案 7 :(得分:0)

在您的情况下memchached可能会遇到一些性能问题。