在Linux上存储和备份1000万个文件

我运行一个网站,其中约1000万个文件(书籍封面)存储在3个子目录中,范围为[0-f]:

0/0/0/ 0/0/1/ ... f/f/f/ 

这导致每个目录大约2400个文件,当我们需要检索一个文件时,这是非常快的。 而且这是许多问题提出的做法。

但是,当我需要备份这些文件时,只需浏览保存10m文件的4k目录就需要很多天。

所以我想知道如果我可以将这些文件存储在一个容器(或在4k容器),这将每个行为完全像一个文件系统(某种挂载的ext3 / 4容器?)。 我想这样做几乎和直接访问文件系统中的文件一样高效,而且这将会非常有效地复制到另一台服务器上。

有关如何做到最好的build议? 或者任何可行的select(noSQL,…)?

快速访问和备份数百万个文件的选项

从类似问题的人借来的

这听起来更像是一个面对USENET新闻服务器和cachingweb代理的更简单的问题:数以百万计的随机访问的小文件。 你可能想从他们那里得到提示(除非他们通常不需要备份)。

http://devel.squid-cache.org/coss/coss-notes.txt

http://citeseer.ist.psu.edu/viewdoc/download;jsessionid=4074B50D266E72C69D6D35FEDCBBA83D?doi=10.1.1.31.4000&rep=rep1&type=pdf

显然,循环新闻文件系统的周期性与您无关,但是具有包装图像的多个磁盘文件/设备和来自用户提供的用于查找位置信息的信息的快速索引的较低级概念是非常合适的。

专用文件系统

当然,这些概念与人们正在讨论的在文件中创build文件系统并将其安装在环回之外的概念是相似的,除非要编写自己的文件系统代码。 当然,既然你说你的系统是大部分读取的,那么实际上你可以用一个磁盘分区(或者lvm分区来确定大小的灵活性)来达到这个目的。 如果要备份,请以只读方式装入文件系统,然后复制分区位。

LVM

我上面提到的LVM是允许dynamic调整分区大小的,因此你不需要备份大量的空闲空间。 但是,当然,LVM还有其他一些可能非常适用的function。 特别是“快照”function,可以让您立即冻结文件系统。 任何意外rm -rf或其他什么都不会干扰快照。 具体取决于你想要做什么,这可能足以满足你的备份需求。

RAID-1

我相信你已经熟悉了RAID,可能已经在使用它来保证可靠性,但是RAID-1也可以用于备份,至less如果你使用的是软件RAID(你可以在硬件RAID中使用它,因为可能需要相同的型号/版本控制器才能读取,因此可靠性较低)。 这个概念是,你创build一个RAID-1组,其中包含比实际需要连接的多一个磁盘,以满足正常的可靠性需求(例如,如果使用具有两个磁盘的软件RAID-1,也可能是一个大磁盘和一个硬件 – 在硬件RAID-5的顶部具有带有软件RAID-1的较小磁盘的RAID5)。 当需要进行备份时,请安装磁盘,请mdadm将该磁盘添加到raid组,等待它指示完整性,可选地要求validation清理,然后删除该磁盘。 当然,根据性能特点,您可以在大部分时间安装磁盘,只能删除与备用磁盘交换的磁盘,或者只能在备份期间安装磁盘)。

您可以使用环回pipe理器挂载虚拟文件系统,但这会加速您的备份过程,这可能会影响正常操作。

另一种方法是使用dd备份整个设备。 例如, dd if=/dev/my_device of=/path/to/backup.dd

你可能知道,你的问题是地方性的。 典型的磁盘search需要10ms左右。 因此,对1000万个随机放置的文件调用“stat”(或打开())需要10万次search,或者大约10万次或30个小时。

所以你必须把你的文件放到更大的容器中,这样相关的数字就是你的驱动器带宽(通常是单个磁盘50-100MB /秒),而不是你的寻道时间。 同样,你可以在它上面添加一个RAID,这可以让你增加带宽(但不会缩短寻道时间)。

我可能不会告诉你任何你不知道的事情,但我的观点是,你的“容器”的想法肯定能解决问题,几乎任何容器都能做到。 Loopback坐骑可能会像任何事情一样工作。

有几个选项。 最简单的,应该与所有的Linux文件系统一起工作,就是把整个分区( /dev/sdb3/dev/mapper/Data-ImageVoldd复制到一个映像中,然后存档该映像。 在还原单一文件的情况下,环回挂载映像( mount -o loop /usr/path/to/file /mountpoint )并复制所需的文件。 对于完整的分区还原,您可以反转最初的dd命令的方向,但是您确实需要相同大小的分区。

从你的使用情况来看,我猜测单个文件恢复是非常罕见的事情,如果它们发生的话。 这就是为什么基于映像的备份在这里真正有用的原因。 如果您确实需要更频繁地进行个别恢复,则使用分阶段LVM快照将会更方便; 但是你仍然需要为那些危急的“我们失去了一切”灾难做基于映像的备份。 基于镜像的恢复往往比基于tar的恢复速度要快得多,因为它只是恢复块,不会因为每个fopen / fclose而产生相当多的元数据操作,而且还可能是高度顺序的磁盘操作进一步加快速度。

或者,正如谷歌的video@casey所指出的那样,XFS是一个伟大的文件系统(如果复杂的话)。 XFS的一个更好的实用工具是xfsdump工具,它将整个文件系统转储到一个文件中,而且通常比tar更快。 这是一个特定于文件系统的实用程序,所以可以利用tar内部不能使用的fs内部函数。

我build议你先尝试升级到EXT4,如果你没有运行它。

谷歌已经做了很多研究, 为什么EXT4是一个好主意 。

之后,您应该考虑部署分布式文件系统体系结构。 例如:

如果您对数据存储的设备型号感到满意,也许可以考虑使用NexentaStor 。 它在OpenSolaris上运行ZFS,但是所有pipe理都是通过Web GUI。

有几个function可以帮助解决您的问题。

  • 企业版支持基于快照的远程复制forms,不需要通过整个文件系统进行扫描。

  • 如果你不介意让自己的手变脏,ZFS有一个非常方便的ZFS diff命令,可以有效地告诉你哪些文件自上次快照以来已经被添加,修改或者删除,而不需要扫描整个文件系统。 您可以将其并入您的备份系统,以大大减less执行增量备份所需的时间。

也许是一个简单的答案,但我的第一个想法是使用类似于MongoDB上构build的GridFS 。 许多主要的语言驱动程序支持开箱即用,因此您应该能够将其与代码的文件读取部分交换出来。 另外,你可以使你现有的目录path成为这些文件的关键。

你可能遇到的一个问题是,如果Mongo一直在从磁盘上寻找,Mongo往往会放慢速度。 有了一千万个文件,我希望你的大部分数据都在磁盘上。 据我所知,GridFS中的文件大小是4MB,所以如果你的文件比这个文件大,那么你将会花费几个昂贵的操作来获得一个文件。 我认为,关键是根据你已经整洁的目录结构分割你的文件,这样你就可以在几个盒子上运行Mongo的几个实例来减轻负载。 但是,我不知道你的性能要求是什么,所以我可能会过度考虑它。

这一切的好处是什么? 与磁盘读取操作非常接近的性能如果操作正确。 而且, Mongo提供了几种优秀的内置方法来快速备份数据库实例中的所有数据,即使数据库仍在运行。

您可以使用标准的dump实用程序来备份大量文件的EXT4文件系统。 此实用程序首先检查文件系统上使用的块,然后按磁盘顺序备份它们,从而消除大部分search。

还有一个相应的restore实用程序用于恢复由dump创build的备份。

它支持增量备份,使用从上一级0(完整)备份修改的级别1备份文件,级别2(从一级备份修改)等等。

对于增量备份,一个选项是为新的封面创build第二个影子树。 也就是说,你将拥有用于所有读操作的主树。 你也有一个newfiles/012345.....jpg目录; 新添加的封面在这里以及在主树中创build一个硬链接。 在执行备份时,您可以偶尔备份主树,但要定期newfiles (更小)的新newfiles树。

请注意,为了保持newfiles树的小,在执行主树的新备份之前,可以清空newfiles树:

 mv newfiles newfiles_ mkdir newfiles rm -rf newfiles_ 

一旦你这样做,当然,你致力于产生一个新的主树的备份。

添加一点点的并发通常是有帮助的。

我有一个和你一样的问题。 在我的情况下,我必须备份大约3000万个文件,其中大部分是HTML,PHP或JPEG文件。 对我来说BackupPC + rsync通过ssh的作品种类确定; 完整备份需要一天左右,但增量通常会在几个小时内完成。

诀窍是将每个主级目录(0,1,2 … a,b,c …)作为新的目标添加到BackupPC中,并让它并行地执行备份,因此它同时备份目录a / ,b / ,c / *等等。 根据您的磁盘子系统,几个进程之间的任何事情到大约10个进程可能是最快的备份方式。

LVM快照和块级备份也是一种select,但通过BackuPC和文件级备份,您仍然可以根据需要恢复单个文件或目录。

本杰明

我认为你的问题可以解决在每个目录级别的文件数量!

如果您将20 000个文件存储在一个目录中,访问时间是否会因重要因素而发生变化?

你是否也将文件系统元数据存储在单独的更快的访问驱动器上?(如SSD)。

我build议一个好的旧的关系数据库,而不是。

我会使用一个PostgreSQL与256分区表(cover_00,cover_01,…,cover_ff)与图像数据作为bytea (二进制)列与外部存储,文件标识符作为主键。 检索一个图像将是快速(感谢主键索引),数据完整性将得到保证(ACID兼容的数据库),备份将在磁盘顺序,所以不要太多的寻求。