我有一个网站,将存储用户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的例子以及Web浏览器的本地caching。
需要注意的一件重要的事情是,在ext2 / 3中,在达到32,000的限制之前,你会开始遇到性能问题,因为目录是线性search的。 移动到另一个文件系统(例如ext4或reiser)将会消除这种效率低下的问题(reiser用二进制分割algorithmsearch目录,所以长时间的目录处理效率要高得多,ext4也可以),以及每个目录的固定限制。
如果你必须ext2 / ext3我看到的唯一的可能性是分割你的数据。 find将您的数据分割成相似大小的可pipe理块的标准。
如果它只是关于configuration文件图像,我会做的:
例如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个目录中的数据,这为三个层次中的每一个提供了快速目录查找。
不是你的问题的直接答案,但需要注意的是未来的参考是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更大的子目录号码。
例如,用模来做任何你想要的东西,哈希。
这样子目录也将被线性填充。