如何解决linux子目录数限制?


9

我有一个网站,它将存储用户个人资料图像。每个图像都存储在特定于用户的目录(Linux)中。目前,我的客户群超过30个,这意味着我将拥有30个以上的文件夹。但是我当前的Linux机器(ext2 / ext3)不支持创建超过32000个目录。我该如何克服?甚至YouTube的家伙也有同样的问题,那就是视频缩略图。但是他们通过迁移到ReiserFS解决了这一问题。我们不能有更好的解决方案吗?

更新:当在IRC中被问到时,人们正在询问将其升级到ext4(极限为64k),当然您甚至也可以超越它。或通过内核修改来更改限制。

更新:如何根据用户ID范围将用户群分为文件夹。在一个文件夹中表示1-1000,在另一个文件夹中表示1000-2000。这似乎很简单。你们怎么说?

坦白说,还有其他办法吗?


1
您为什么不想更改文件系统?如果这是ext2 / 3的限制,则除了更改文件系统或将当前FS拆分为更多更小的FS(更多不同的挂载点)外,您将没有任何其他更改。
Manuel Faux

1
曼努埃尔(Manuel):如果他更改文件系统,则将特定的FS绑定到他的应用程序。尽管最终可能会找到答案,但我认为这可能是需要在应用程序级别解决的问题。如果您需要破解内核或文件系统,除非有非常特殊的要求,否则您可能走错了路。
凯尔·布​​兰特

Answers:


16

该限制是针对每个目录的,而不是针对整个文件系统的,因此您可以通过进一步细分来解决此问题。例如,不是让所有用户子目录都位于同一目录中,而是按照名称的前两个字符将它们拆分,因此您将具有以下内容:

top_level_dir
|---aa
|   |---aardvark1
|   |---aardvark2
|---da
|   |---dan
|   |---david
|---do
    |---don

更好的办法是创建某种形式的名称哈希并将其用于除法。这样,您就可以更好地在目录之间进行分配,而不是使用首字母示例,例如“ da”非常满,而“ zz”完全空白。例如,如果您使用CRC或MD5的名称并使用前8位,则会得到类似以下内容:

top_level_dir
|---00
|   |---some_username
|   |---some_username
|---01
|   |---some_username
...
|---FF
|   |---some_username

可以根据需要将其扩展到其他深度,例如,如果使用用户名而不是哈希值,则可以这样:

top_level_dir
|---a
|   |---a
|       |---aardvark1
|       |---aardvark2
|---d
    |---a
    |   |---dan
    |   |---david
    |---o
        |---don

此方法在很多地方都使用过,例如鱿鱼的缓存,复制路德维希的示例以及Web浏览器的本地缓存。

需要注意的重要一件事是,使用ext2 / 3时,由于线性搜索目录,因此您将开始遇到性能问题,直到您接近32,000个限制。转移到另一个文件系统(例如ext4或reiser)将消除这种效率低下(reiser搜索具有二进制分割算法的目录,以便长距离目录被更有效地处理,而ext4也可以这样做)以及每个目录的固定限制。


刚刚更新了问题描述,使其包含以下内容:“更新:如何根据用户ID范围将用户群分为多个文件夹。一个文件夹中的1-1000,另一个文件夹中的1000-2000。这似乎很简单。你说吗?
无-2009年

1
如果通常通过用户ID而不是用户名(或用户名)来标识用户,那将很好地工作,并且比哈希更有效。尽管如果您始终在系统中的其他位置使用名称来引用它们,则必须在各处添加额外的name-> id查找。
David Spillett

谢谢大卫!我尝试了不同的解决方案。我几乎没有创建4个文件夹,其范围为1-30000、30000-60000等。我认为从如此大的目录中获取文件比从具有1000个文件的目录中花费更多的时间(以前的方法)。你说什么?
无– 2009年

1
这取决于文件系统。如果您使用的是ext2或ext3,那么我建议每个目录小于30,000。一些工具会发出大约10,000条警告。您可以在ext3 / 4中打开目录索引以提供帮助:tune2fs -O dir_index / dev / <volumename>,但是我只是建议将目录中的对象数减少一些(几千个或更少?) 。
David Spillett

@Maddy,由于在Ext2 / 3处理大量文件的方式上存在其他限制,因此您需要此解决方案。有关详细信息,请参阅serverfault.com/questions/43133/…。将名称拆分为“ buckets-as-subdirectorys”可以缓解最终会遇到的其他问题。请注意,这与Squid首次设置对象缓存时使用的策略相同-例如,作为一个示例,每个64个目录中都有64个目录。
艾利·佩恩

7

如果您绑定到ext2 / ext3,那么我看到的唯一可能性就是对数据进行分区。查找将数据分成大小相似的可管理块的条件。

如果只是关于个人资料图片,我会这样做:

  1. 使用图像的哈希值(例如SHA1)
  2. 使用SHA1作为文件和目录名称

例如,SQUID高速缓存以这种方式执行此操作:

f / 4b / 353ac7303854033

顶级目录是第一个十六进制数字,第二级是接下来的两个十六进制数字,文件名是其余的十六进制数字。


2

无法找到更好的解决方案?

您确实有更好的解决方案-使用不同的文件系统,有很多可用的文件系统,其中许多文件针对不同的任务进行了优化。正如您指出的那样,ReiserFS经过优化,可以处理目录中的许多文件。

请参阅此处以比较文件系统。

只是很高兴您没有被NTFS困扰,NTFS对于目录中的许多文件确实是非常糟糕的。如果您不喜欢使用相对较新(但显然稳定)的ext4 FS,则建议使用JFS作为替代。


您是否拥有指向NTFS文件系统性能的良好链接?
托尔比约恩Ravn的安徒生

是的,除了使用该应用程序的个人经历之外,该应用程序在目录中创建新文件的时间过长。(花了几个小时将它们全部删除),并且通过将目录中的文件数限制为1000,提高了Subversion的性能。 :support.microsoft.com/kb/130694我不认为他们曾经“修复”此问题,因为它仍然是一种性能。调整NTFS。
gbjbaanb

1

个人资料图片是否小?如何将其与其他概要文件数据一起放入数据库中?这可能不是您的最佳选择,但值得考虑...

这是有关该主题的(较旧的)Microsoft白皮书:否BLOB


1

我已经一起捣破了一个小型网络画廊,结果在这里我变了个问题。我“仅”在高速缓存目录中有约30.000张图像,事实证明这相当慢(据我所知,ext2使用链表作为目录索引)。

我最终按照以下方式做点事情:

def key2path(key):
    hash = md5(key)
    return os.path.join(hash[0], hash[1], key)

这样会将数据划分为256个目录,从而可以对三个级别的每个目录进行快速目录查找。

  • 我选择在SHA-1上使用MD5,因为如果您更改32的任何12位,MD5会保证输出不同,所以我发现它非常适合哈希用户名,目录和其他简短内容。而且速度也很快...
  • 我不包括整个哈希,因为它将产生太多目录,并一遍又一遍地浪费磁盘缓存。

1
您可能会使用更简单的散列,例如CRC,因为散列不需要像MD5或SHA那样具有强大的密码强度……但是无论如何,性能差异还是可以忽略的……
sleske,2009年

0

OpenBSD链接的项目“ Epitome”不是您问题的立即解决方案,但值得您将来参考

Epitome是提供单实例存储,内容可寻址存储和重复数据删除服务的引擎。

您所有的数据都以散列块的形式存储在数据存储中,从而消除了非唯一的块以减少空间使用,并让您实质上无需考虑存储机制,因为您只需通过UUID从数据存储中请求内容即可。

Epitome目前处于试验阶段,但有待观察。


0

通常,您要避免目录中包含大量文件/目录。主要原因是命令行上的通配符扩展会导致“参数过多”错误,从而在尝试使用这些目录时会造成很多麻烦。

寻求一种可以使树更深但更窄的解决方案,例如,通过创建类似其他描述的子文件夹。


0

我们有一个类似的问题,如前所述,解决方案是创建目录层次结构。

当然,如果您有一个依赖于平面目录结构的复杂应用程序,则可能需要进行大量修补。因此,很高兴知道有一种解决方法,请使用没有提到的32k限制的符号链接。然后,您就有足够的时间来修复应用程序...


0

为什么不使用时间戳方法,然后使用溢出选项。

例如

因此,可以说您的时间戳为:1366587600

省略最后两位数字(否则,它会变得有点荒谬)。将图章分成4组(目录数不应超过9999-如果需要,可以将其分开)。

这应该给您留下这样的东西:

/files/1366/5876/

然后,在上传之前检查dir中的数量,如果上传数量很多(即每100秒32000 +),则以第二个或一个字母迭代目录,例如:

/files/1366/5876/a/file.txt

要么

/files/1366/5876/00/file.txt

然后将时间戳+字母或完整的路径代码与用户一起登录到db中,然后进行设置。

pathstamp:1366587600或13665876a(如果使用字母)。

最终会出现大量目录,但是对于处理文件修订版确实很有用。例如,如果用户要使用新的个人资料图片,则您仍然可以使用旧的带有时间戳的旧版本,以防他们希望撤消更改(不仅仅是被覆盖)。


0

我建议确定您要(或可以)在父文件夹中有多少个最大子目录。

然后,您需要转换您的用户ID,以便从1开始。

然后,您可以执行以下操作: modulo = currentId % numberOfSubdirectories

modulo现在将包含您的子目录号,该数字将永远不会比numberOfSubdirectories您选择的大。

例如,对模进行任何想做的事情,对它进行哈希处理。

同样,子目录也将线性填充。

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.