我有一个网站,用于存储用户个人资料图片。每个图片都存储在特定于用户的目录 (Linux) 中。目前,我有 30 多个客户群,这意味着我将有 30 多个文件夹。但我当前的 Linux 机器 (ext2/ext3) 不支持创建超过 32000 个目录。我该如何解决这个问题?甚至 YouTube 用户也遇到了同样的问题,视频缩略图也是如此。但他们通过迁移到 ReiserFS 解决了这个问题。难道我们没有更好的解决方案吗?
更新:在 IRC 中询问时,人们询问将其升级到 ext4 的可能性,因为 ext4 有 64k 的限制,当然你甚至可以克服这一点. 或者通过修改内核来改变限制。
更新:如何根据用户 ID 范围将用户群拆分为文件夹。这意味着 1-1000 放在一个文件夹中,1000-2000 放在另一个文件夹中。这似乎很简单。你们觉得怎么样?
说实话,难道没有其他办法吗?
答案1
该限制是针对每个目录的,而不是针对整个文件系统的,因此您可以通过进一步细分来解决它。例如,不是让同一目录中的所有用户子目录都按照名称的前两个字符进行拆分,而是像这样:
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
此方法在很多地方使用,例如 squid 的缓存、复制 Ludwig 的示例以及 Web 浏览器的本地缓存。
需要注意的一件重要事情是,使用 ext2/3 时,在接近 32,000 的限制之前,您就会开始遇到性能问题,因为目录是线性搜索的。移动到另一个文件系统(例如 ext4 或 reiser)将消除这种低效率(reiser 使用二进制分割算法搜索目录,因此只要目录得到更高效的处理,ext4 也可以这样做)以及每个目录的固定限制。
答案2
如果您必须使用 ext2/ext3,我认为唯一的可能性就是对数据进行分区。找到一个标准,将您的数据分割成大小相似的可管理块。
如果仅涉及个人资料图片,我会这样做:
- 使用图像的哈希值(例如 SHA1)
- 使用 SHA1 作为文件和目录名称
例如 SQUID 缓存是这样实现的:
f/4b/353ac7303854033
顶级目录是第一个十六进制数字,第二级目录是接下来的两个十六进制数字,文件名是剩下的十六进制数字。
答案3
我们不能有更好的解决办法吗?
您确实有更好的解决方案 - 使用不同的文件系统,有很多可用的文件系统,其中许多针对不同的任务进行了优化。正如您所指出的,ReiserFS 针对处理目录中的大量文件进行了优化。
看这里用于文件系统的比较。
只是庆幸你没有被 NTFS 困住,因为 NTFS 对于目录中的大量文件来说确实很糟糕。如果你不喜欢使用相对较新(但显然很稳定)的 ext4 FS,我建议使用 JFS 作为替代品。
答案4
通常,您要避免目录中有大量文件/目录。主要原因是命令行上的通配符扩展会导致“参数过多”错误,从而导致在尝试处理这些目录时非常麻烦。
寻找一种可以制作更深但更窄的树的解决方案,例如通过创建其他人描述的子文件夹。