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


25

我经营一个网站,该网站在3个级别的子目录中存储大约1000万个文件(书籍封面),范围为[0-f]:

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

这导致每个目录大约2400个文件,这在我们需要检索一个文件时非常快。此外,这是许多问题建议的做法。

但是,当我需要备份这些文件时,只需要花几天时间浏览包含10m个文件的4k目录。

因此,我想知道是否可以将这些文件存储在一个容器(或4k容器)中,每个容器的行为都完全类似于文件系统(某种已安装的ext3 / 4容器?)。我想这几乎与直接访问文件系统中的文件一样有效,并且这将具有非常有效地被复制到另一台服务器的巨大优势。

关于如何做到最好的任何建议?还是任何可行的替代方法(noSQL,...)?


您现在正在使用什么文件系统?
cmcginty 2011年

如果您可以负担价格,则NetApp可以作为一种选择
Ian

我在CentOS 5.6下使用ext4
Benjamin

1
奇怪为什么为什么要花很多时间才能浏览保存10m个文件的4k目录,这似乎太慢了。假设每个路径名150个字节,那么10m文件名将产生1.5 GB的数据,因此它可能是可用的内存/ CPU(包括对结果进行排序)。另外,请检查启用/禁用dir_index是否有帮助:lonesysadmin.net/2007/08/17/…以及serverfault.com/questions/183821/…的
RichVel 2011年

注意5年后:我已将所有内容迁移到Amazon S3,它非常适合存储如此大量的文件。另外,我不必再将文件分成3个级别的子目录,至于S3,它没有什么区别(路径就是路径,是否包含斜杠都没有影响)。知道我的数据已在多个位置安全地复制,因此我可以睡得更好。
本杰明

Answers:


11

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

从有类似问题的人那里借钱

这听起来很像是USENET新闻服务器和缓存Web代理所面临的一种更简单的问题:数亿个随机访问的小文件。您可能希望从他们那里得到一些提示(除非他们通常不必进行备份)。

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

显然,循环新闻文件系统的循环性质与您无关,但是具有多个磁盘文件/设备(带有打包映像)和用户提供的信息来查找位置信息的快速索引的较低层概念非常合适。

专用文件系统

当然,这些只是与人们谈论的在文件中创建文件系统并通过环回挂载而讨论的概念类似的概念,只是您需要编写自己的文件系统代码。当然,由于您说的系统是只读的,因此实际上可以将磁盘分区(或lvm分区,以便灵活调整大小)专用于此目的。当您要备份时,以只读方式挂载文件系统,然后复制分区位。

LVM

我在上面提到LVM对于允许动态调整分区大小很有用,这样您就无需备份大量的空白空间。但是,当然,LVM具有其他可能非常适用的功能。特别是“快照”功能,可让您及时冻结文件系统。任何意外事件rm -rf或任何不会干扰快照的事件。根据您要尝试执行的操作,这可能足以满足您的备份需求。

RAID-1

我确定您已经熟悉RAID,并且可能已经将其用于可靠性,但是RAID-1也可以用于备份,至少在使用软件RAID的情况下(可以将其与硬件RAID一起使用,但是实际上可靠性较低,因为可能需要读取相同的模型/修订版控制器。其概念是,创建一个RAID-1组时,其磁盘数量要比出于正常可靠性需要实际需要连接的磁盘数量多(例如,如果您使用带有两个磁盘的软件RAID-1,或者是一个较大的磁盘和一个硬件,则为第三块磁盘,具有较小磁盘的RAID5,在硬件RAID-5之上具有软件RAID-1)。需要备份时,请安装磁盘,请mdadm将该磁盘添加到raid组,等待直到表明完整性,然后选择进行验证清理,然后取出磁盘。当然,


非常完整的答案,总结了好的解决方案。我想我将保留现有的文件系统结构,并使用LVM快照,这对于我的用例而言似乎是完美的。
本杰明

9

您可以使用回送管理器挂载虚拟文件系统,但这虽然可以加快备份过程,但可能会影响正常操作。

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


+1备份设备本身是个好主意。
ASM

3
如果使用此方法,则应测试还原(当然,应始终这样做),因为如果输入是/ dev / sdd之类的磁盘,则dd将存储分区sheme和大小。如果将其还原到较小的磁盘上,则会出现错误,并且如果将其还原到较大的磁盘上,它将显示为截断状态。如果您将数据还原到相同磁盘类型的另一个示例,则将是最好的方法。仅还原分区(/ dev / sdd1)会减少麻烦。
用户未知,

1
请注意,如果设备位于LVM上,则也可以在不使用LVM快照卸载磁盘的情况下执行备份。
bdonlan

我第二次使用LVM快照备份方法。过去,我利用lvm进行实时DR复制。将dd与快照结合使用可轻松进行快速的块级备份。
slashdot

我尝试dd了一下nc,这做得很好!但是,与使用LVM快照而不是实时分区相反,我的数据可能不一致/损坏。
本杰明

8

如您所知,您的问题是本地性。典型的磁盘寻道需要10毫秒左右。因此,仅对1000万个随机放置的文件调用“ stat”(或open())就需要进行1000万次搜索,即大约100000秒或30个小时。

因此,您必须将文件放入更大的容器中,以使相关数字是驱动器带宽(单个磁盘通常为50-100 MB /秒)而不是查找时间。另外,您还可以在其上放置RAID,从而提高带宽(但不会减少寻道时间)。

我可能不会告诉您您尚不知道的任何内容,但是我的意思是,您的“容器”想法肯定会解决问题,并且几乎任何容器都可以。环回安装可能会正常工作。


是的,位置至关重要。查看您的使用模式。大多数问题倾向于遵循帕累托原理(80%的进程占用20%的数据),因此,如果您能确定哪些文件需要缓存在RAM中,或者只是放在具有不同目录布局的单独分区上,那么它需要较少的目录查找或查找,可能会很有帮助。将经常访问的文件分散在磁盘的不同轴上,以便可以并行执行查找也可能会有所帮助。@nemo +1,用于显示参考位置。
Marcin

5

有两种选择。最简单且应与所有Linux文件系统一起使用的是dd将整个分区(/dev/sdb3/dev/mapper/Data-ImageVol)复制到单个映像并对该映像进行存档。如果要还原单个文件,请环回安装映像(mount -o loop /usr/path/to/file /mountpoint)并复制出所需的文件。对于完整分区还原,您可以反转初始dd命令的方向,但实际上确实需要一个大小相同的分区。

从您的用例来看,我猜单个文件恢复是很少发生的事件,即使它们确实发生过。这就是为什么基于映像的备份在这里真正有意义的原因。如果确实需要更频繁地进行单个还原,则使用分段LVM快照会更加方便;但是您仍然需要为那些严重的“我们丢失了一切”灾难进行基于映像的备份。基于图像的恢复往往走了不少不是基于焦油的恢复仅仅是因为它只是恢复块,它不在产生相当多的元数据操作的每FOPEN / FCLOSE更快,也可以是一个高度连续盘操作进一步提高速度。

另外,正如Google视频@casey所提到的那样,XFS是一个很棒的文件系统(如果很复杂)。带有XFS的更好的实用程序之一是xfsdump实用程序,该实用程序会将整个文件系统转储到单个文件中,并且通常比这样做的速度更快tar。它是特定于文件系统的实用程序,因此可以以tar无法使用的方式利用fs内部。


那里有很多好的答案!XFS似乎很有趣,但恐怕有点超出我的能力范围。
本杰明


2

也许是一个简单的答案,但是我的第一个想法是使用诸如MongoDB上内置的GridFS之类的东西。许多主要语言驱动程序都开箱即用地支持它,因此您应该能够将其与代码的文件读取部分交换出来。同样,您可以仅使现有目录路径将这些文件的关键字作为路径。

您可能会遇到的一个问题是,如果Mongo一直在从磁盘中寻找数据,那么它往往会很快降低速度。拥有1000万个文件,我希望您的大多数数据都将存储在磁盘上。我记得,GridFS中的文件块为4MB,因此,如果文件大于此大小,则将执行一些昂贵的操作来获得一个文件。我认为,关键是根据已经整洁的目录结构来分片文件,以便可以在数个盒子上运行多个Mongo实例以减轻负载。但是,我也不知道您对性能的要求是什么,因此我可能考虑得过多。

所有这些的好处是什么?如果操作正确,则性能与磁盘读取非常接近。另外,Mongo具有多种出色的内置方法,可以快速备份数据库实例中的全部数据,即使数据库仍在运行。


肯定会看看我不知道的GridFS,但是我想我最终将保留所有基于文件系统的文件,以减少工作量,因为一切都已经开始了!
本杰明

1

如果您对用于数据存储的设备模型感到满意,则可以考虑使用NexentaStor。它在内部的OpenSolaris上运行ZFS,但是所有管理都是通过Web GUI进行的。

有几个功能可以解决您的问题。

  • 企业版支持一种基于快照的远程复制形式,不需要对整个文件系统进行扫描。

  • 如果您不介意动手,ZFS会提供一个非常方便的ZFS diff命令,该命令可以高效地告诉您自上次快照以来已添加,修改或删除了哪些文件,而无需扫描整个文件系统。您可以将其合并到备份系统中,以大大减少执行增量备份所需的时间。


谢谢,来看看吧。也许这会增加我的项目的复杂性!
本杰明

1

您可以使用标准dump实用程序来备份包含大量文件的EXT4文件系统。该实用程序首先检查文件系统上使用了哪些块,然后按磁盘顺序备份它们,从而消除了大多数查找。

有一个相应的restore实用程序,用于还原由创建的备份dump

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


0

对于增量备份,一种选择是拥有另一棵用于新封面的影子树。也就是说,您将拥有用于所有读取操作的主树。您还将有一个newfiles/012345.....jpg目录。新添加的封面可在此处和主树中创建硬链接。执行备份时,您可以偶尔备份主树,但是可以newfiles更定期地备份(小得多)的树。

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

mv newfiles newfiles_
mkdir newfiles
rm -rf newfiles_

当然,一旦完成此操作,您将致力于生成主树的新备份。


有趣的方法,感谢您的分享。但是,恐怕会在应用程序中涉及很多更改,并且很难将应用程序和存储需求保持在两个单独的层中。
本杰明

0

添加一点并发通常会有所帮助。

我和你有类似的问题。就我而言,我必须备份大约3000万个文件,其中大多数是HTML,PHP或JPEG文件。对我来说,通过SSH的BackupPC + rsync可以正常工作;完全备份大约需要一天的时间,但是增量备份通常会在几个小时内完成。

诀窍是将每个主级别目录(0、1、2 ... a,b,c ...)添加为要复制到BackupPC的新目标,并使其并行执行备份,因此它同时备份目录a / ,b /,c / *等。根据磁盘子系统的不同,从几个进程到大约10个进程之间的任何操作可能都是最快的备份方法。

LVM快照和块级备份也是一种选择,但是使用BackuPC和文件级备份,您仍然可以根据需要还原单个文件或目录。


我很惊讶同时备份根目录可以为您解决问题,我希望这样做实际上会更慢。所有目录都在同一磁盘上吗?您正在使用SSD吗?
本杰明

数据文件存储在SAN中。
Janne Pikkarainen

好的,从现在开始,您可以通过同时访问多个文件来提高效率,因为不同的文件夹很可能物理上位于SAN中的不同驱动器上,或者至少是复制在多个驱动器上,从而允许并发访问。我仅基于RAID-1,因此我猜在两次并发访问之上,我的速度很可能会下降。
本杰明

0

本杰明

我认为您的问题可以通过每个目录级别的文件数解决!

如果在目录中存储2万个文件,访问时间是否会发生很大的变化?

您是否还在将文件系统元数据存储在单独的快速访问驱动器上(例如SSD)?


0

我建议改用一个好的旧关系数据库。

我将使用PostgreSQL,例如256个分区表(cover_00,cover_01,...,cover_ff),其中图像数据作为bytea具有外部存储的(二进制)列,并且文件标识符作为主键。检索映像将很快(由于主键上有索引),可以保证数据完整性(符合ACID的数据库),备份将按磁盘顺序进行,因此无需过多查找。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.