在文件系统中存储一百万张图像

s.m*_*hai 80 storage ntfs images

我有一个将生成大量图像的项目。大约 1,000,000 开始。它们不是大图像,所以一开始我会将它们全部存储在一台机器上。

您如何建议有效地存储这些图像?(目前是 NTFS 文件系统)

我正在考虑一个命名方案...一开始,所有图像都将有一个从 1 开始的增量名称,我希望这将有助于我以后在需要时对它们进行排序,并将它们放在不同的文件夹中。

什么是更好的命名方案:

a/b/c/0 ... z/z/z/999

或者

a/b/c/000 ... z/z/z/999

对此有什么想法吗?

Juh*_*älä 73

我建议使用常规文件系统而不是数据库。使用文件系统比使用数据库更容易,您可以使用普通工具访问文件,文件系统是为这种用途而设计的。NTFS 作为存储系统应该可以正常工作。

不要存储数据库的实际路径。最好将图像的序列号存储到数据库中,并具有可以从序列号生成路径的功能。例如:

 File path = generatePathFromSequenceNumber(sequenceNumber);
Run Code Online (Sandbox Code Playgroud)

如果您需要以某种方式更改目录结构,则更容易处理。也许你需要将图像移动到不同的位置,也许你的空间用完了,你开始在磁盘 A 上存储一些图像,在磁盘 B 上存储一些等等。更改一个函数比更改数据库中的路径更容易.

我会使用这种算法来生成目录结构:

  1. 首先用前导零填充序列号,直到至少有 12 位字符串。这是您的文件的名称。您可能想要添加一个后缀:
    • 12345 -> 000000012345.jpg
  2. 然后将字符串拆分为 2 或 3 个字符块,其中每个块表示一个目录级别。具有固定数量的目录级别(例如 3):
    • 000000012345 -> 000/000/012
  3. 将文件存储到生成的目录下:
    • 因此,具有序列 id 的文件的完整路径和文件名123000/000/012/00000000012345.jpg
    • 对于具有序列 ID12345678901234的文件,路径为123/456/789/12345678901234.jpg

关于目录结构和文件存储需要考虑的一些事项:

  • 上述算法为您提供了一个系统,其中每个叶目录最多包含 1000 个文件(如果您的文件总数少于 1 000 000 000 000 个)
  • 一个目录可以包含的文件和子目录的数量可能有限制,例如Linux上的ext3 文件系统每个目录限制为 31998 个子目录。
  • 如果每个目录有大量文件 (> 1000),普通工具(WinZip、Windows 资源管理器、命令行、bash shell 等)可能无法正常工作
  • 目录结构本身会占用一些磁盘空间,因此您不需要太多目录。
  • 使用上述结构,如果您碰巧弄乱了目录结构,只需查看文件名,您总是可以找到图像文件的正确路径。
  • 如果您需要从多台机器访问文件,请考虑通过网络文件系统共享文件。
  • 如果删除大量文件,上述目录结构将不起作用。它在目录结构中留下了“漏洞”。但是由于您没有删除任何文件,所以应该没问题。

  • 使用散列(例如 MD5)作为文件名以及目录分布是可行的。不仅文件的完整性是命名方案的附带好处(易于检查),而且您将在整个目录层次结构中合理均匀分布。因此,如果您有一个名为“f6a5b1236dbba1647257cc4646308326.jpg”的文件,您可以将其存储在“/f/6”(或您需要的深度)中。2 层深度提供 256 个目录,或者对于最初的 1m 文件,每个目录有不到 4000 个文件。将重新分配自动化到更深层次的方案也很容易。 (38认同)

Sat*_*ppy 31

我将把我的 2 美分放在一条负面建议上:不要使用数据库。

我多年来一直在使用图像存储数据库:大型(1 meg->1 gig)文件,经常更改,文件的多个版本,经常访问。您在存储大文件时遇到的数据库问题处理起来极其繁琐,写入和事务问题很棘手,而且您会遇到可能导致重大火车失事的锁定问题。我必须以书面形式DBCC脚本,然后从备份中恢复的表比任何正常的人应该多练习永远有。

我使用过的大多数较新的系统都将文件存储推送到文件系统,并且仅依靠数据库进行索引。文件系统旨在承受这种滥用,它们更容易扩展,如果一个条目损坏,您很少会丢失整个文件系统。

  • 你看过 SQL 2008 的 FILESTREAM 数据类型吗?它是数据库和文件系统存储之间的交叉。 (5认同)

小智 12

理想情况下,您应该对各种结构的随机访问时间进行一些测试,因为您的特定硬盘驱动器设置、缓存、可用内存等会改变这些结果。

假设您可以控制文件名,我会将它们按每个目录 1000 的级别进行分区。您添加的目录级别越多,您烧录的 inode 就越多,因此这里有一个推拉。

例如,

/root/[0-99]/[0-99]/文件名

请注意,http://technet.microsoft.com/en-us/library/cc781134(WS.10).aspx有关于 NTFS 设置的更多详细信息。特别是,“如果您在 NTFS 文件夹中使用大量文件(300,000 或更多),请禁用短文件名生成以获得更好的性能,尤其是当长文件名的前六个字符相似时。”

您还应该考虑禁用不需要的文件系统功能(例如,上次访问时间)。 http://www.pctools.com/guides/registry/detail/50/

  • +1 用于禁用 8.3 文件名生成和上次访问时间;当我阅读“大量的[文件]”和“NTFS”(Windows)时,首先想到的是这些。 (3认同)

3di*_*nce 12

我认为大多数必须处理这个问题的网站使用某种哈希来确保文件在文件夹中均匀分布。

因此,假设您有一个类似这样的文件的哈希值,515d7eab9c29349e0cde90381ee8f810
您可以将其存储在以下位置,并且您可以使用所需的深度级别来保持每个文件夹中的文件数量较少。
\51\5d\7e\ab\9c\29\349e0cde90381ee8f810.jpg

我已经多次看到这种方法。您仍然需要一个数据库来将这些文件哈希映射到一个人类可读的名称以及您需要存储的其他元数据。但是这种方法可以很好地扩展 b/c,您可以开始在多台计算机和/或存储池等之间分配哈希地址空间。

  • Git 使用类似的方法:https://git-scm.com/book/en/v2/Git-Internals-Git-Objects(支持这个答案) (2认同)

小智 7

无论您做什么,都不要将它们全部存储在一个目录中。

根据这些图像名称的分布,您可以创建一个目录结构,其中有单个字母的顶级文件夹,其中您将有另一组子文件夹用于图像的第二个字母等。

所以:

文件夹img\a\b\c\d\e\f\g\将包含以“abcdefg”等开头的图像。

您可以介绍自己所需的适当深度。

这个解决方案的伟大之处在于目录结构有效地就像一个哈希表/字典。给定一个图像文件名,您将知道它的目录,并且给定一个目录,您将知道那里的图像子集。

  • 做 a\b\c\d\e\f\g 使得目录结构非常深,每个目录只包含几个文件。最好在每个目录级别使用多个字母,例如 ab\cd\ef\ 或 abc\def\。目录还会占用磁盘空间,因此您不需要太多。 (5认同)
  • 和 +1 表示“不要将它们全部存储在一个目录中”。我支持的旧系统在服务器上的单个文件夹中放置了超过 47000 个文件,资源管理器大约需要一分钟才能打开该文件夹。 (3认同)
  • 我必须支持一个目录中包含 4+ 百万个文件的应用程序;它运行得非常好,但您永远无法让资源管理器打开文件夹,它会不断对新添加的内容进行排序。+1 表示 NTFS 能够在不死的情况下处理它。 (2认同)

小智 6

我们有一个包含 400 万张图片的照片存储系统。我们仅将数据库用于元数据,所有图像都使用反向命名系统存储在文件系统上,其中文件夹名称从文件的最后一位、last-1 等生成。例如:000001234.jpg 存储在目录结构中,如 4\3\2\1\000001234.jpg。

该方案与数据库中的标识索引配合得非常好,因为它均匀地填充了整个目录结构。


小智 5

我会将这些存储在文件系统上,但这取决于文件数量增长的速度。这些文件是否托管在网络上?有多少用户会访问这些文件?在我给你一个更好的建议之前,这些是需要回答的问题。我也会看看 Facebook 的 Haystack,他们有一个非常好的解决方案来存储和提供图像。

此外,如果您选择文件系统,您将需要使用目录对这些文件进行分区。我一直在研究这个问题并提出了一个解决方案,但无论如何它都不是完美的。我正在按哈希表和用户进行分区,您可以在我的博客上阅读更多内容。


小智 5

新的 MS SQL 2008 具有处理此类情况的新功能,称为 FILESTREAM。看一看:

Microsoft TechNet 文件流概述