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

我有一个网站,将存储用户configuration文件图像。 每个图像都存储在特定于用户的目录(Linux)中。 目前我有30多个客户群,这意味着我将有30多个文件夹。 但是我目前的Linux机器(ext2 / ext3)不支持创build超过32000个目录。 我怎么能通过这个? 即使YouTube的家伙也有同样的问题,与video缩略图。 但是他们通过转向ReiserFS解决了这个问题。 我们不能有更好的解决scheme吗?

更新:当被问及IRC时,人们会问是否将其升级到ext4,其中有64k的限制,当然你甚至可以通过 。 或内核黑客更改限制。

更新:如何根据用户标识范围将用户基础分为多个文件夹。 一个文件夹的含义是1-1000,另一个是1000-2000。 这似乎很简单。 你说什么,伙计?

坦率地说,没有其他办法吗?

这个限制是每个目录,而不是整个文件系统,所以你可以通过进一步的细分来解决这个问题。 例如,不要将所有的用户子目录都放在同一个目录中,而是按照名称的前两个字符来分割它们,所以你有这样的东西:

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

更好的办法是创build一些名称的散列forms,并将其用于分区。 通过这种方式,您可以在目录之间获得更好的传播效果,而不是以最初的字母为例,“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 

这个方法被用在很多地方,比如squid的caching,复制Ludwig的例子以及We​​b浏览器的本地caching。

需要注意的一件重要的事情是,在ext2 / 3中,在达到32,000的限制之前,你会开始遇到性能问题,因为目录是线性search的。 移动到另一个文件系统(例如ext4或reiser)将会消除这种效率低下的问题(reiser用二进制分割algorithmsearch目录,所以长时间的目录处理效率要高得多,ext4也可以),以及每个目录的固定限制。

如果你必须ext2 / ext3我看到的唯一的可能性是分割你的数据。 find将您的数据分割成相似大小的可pipe理块的标准。

如果它只是关于configuration文件图像,我会做的:

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

例如SQUIDcaching就是这样做的:

F / 4B / 353ac7303854033

顶级目录是第一个hex数字,第二个级别是接下来的两个hex数字,文件名是剩余的hex数字。

我们有一个更好的解决scheme吗?

你有一个更好的解决scheme – 使用不同的文件系统,有很多可用的,其中许多是针对不同的任务进行了优化。 正如你所指出的,ReiserFS已经过优化,可以处理目录中的大量文件。

在这里查看文件系统的比较。

只是很高兴你没有被困在NTFS中,这对于目录中的许多文件来说确实是一个糟糕的结果。 如果你不喜欢使用相对较新(但表面上很稳定)的ext4 FS,我推荐使用JFS。

configuration文件图像很小? 把数据库中的其余数据放在数据库里怎么样? 这可能不是您的最佳select,但值得考虑…

这是一个(旧的)微软白皮书的话题: BLOB或不BLOB 。

我曾经在一个小型的networking画廊里面混淆了一下,在这里我遇到了这个问题的一个变种。 我“只”有〜30.000图像在caching目录,这是相当缓慢(ext2使用目录索引链接列表,我记得它)。

我最终做了这样的事情:

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

这将分割256个目录中的数据,这为三个层次中的每一个提供了快速目录查找。

  • 我select通过SHA-1使用MD5,因为如果你改变了32位的任何12位,MD5保证了不同的输出,所以我觉得它适合散列用户名,目录和其他短的东西。 而且速度也很快
  • 我不包括整个散列,因为它会产生太多的目录,并且反复有效地清理磁盘caching。

不是你的问题的直接答案,但需要注意的是未来的参考是OpenBSD链接的项目“Epitome”

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

所有数据都以散列块的forms存储在数据存储区中,删除非唯一的块以减less空间使用量,并允许您基本上忘记存储机制,因为您可以通过UUID简单地请求数据存储区中的内容。

Epitome目前是实验性的,但是可以预见未来。

通常你想避免拥有大量文件/目录的目录。 主要原因是命令行上的通配符扩展会导致“太多的参数”错误,导致尝试使用这些目录时非常痛苦。

寻找一个解决scheme,使更深,但更窄的树,例如通过创build像其他人描述的子文件夹。

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

当然,如果你有一个复杂的应用程序依赖于一个平面的目录结构,你可能需要很多补丁。 所以知道有一个解决方法是很好的,使用没有提到32k限制的符号链接。 那么你有足够的时间来修复应用程序…

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

例如

所以可以说你的时间戳是:1366587600

省略最后2位数字(否则只是略微荒谬)。 将邮票分成4组(目录数量不应超过9999个 – 如果你想分开)。

这应该给你这样的东西:

 /files/1366/5876/ 

然后在上传之前检查目录中的数量,如果获得大量的上传(即每100秒32000 +),然后通过第二个或一个字母来遍历目录,例如:

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

要么

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

然后将时间戳+字母或完整path代码与用户一起logging到数据库中,您应该设置。

path戳:1366587600或13665876a(如果您使用的是字母)。

这确实会导致大量的目录,但是它对于处理文件修订可能非常有用。 例如,如果用户想要使用新的个人资料图片,则仍旧使用旧的时间戳版本,以防万一他们希望撤销更改(不只是覆盖)。

我会build议决定有多less最大的子目录,你想(或可以)在父文件夹中。

那么你需要转换你的用户名,所以他们从1开始。

那么你可以这样做: modulo = currentId % numberOfSubdirectories

modulo现在将包含您永远不会比您select的numberOfSubdirectories更大的子目录号码。

例如,用模来做任何你想要的东西,哈希。

这样子目录也将被线性填充。