文件主机的目录结构

时间:2009-03-05 02:08:13

标签: php linux filesystems

我有一个简单的文件主机,它会为文件提供唯一的ID,并将它们存储在一个目录中。我被告知这将在未来引起问题,我想知道我应该注意哪些事情,以确保它能够顺利地运行到未来及以后。

此外,是否存在通过发送标头信息和readfile()强制下载的性能问题?保留文件名并允许直接下载使用不是使用脚本会更好吗?

由于

5 个答案:

答案 0 :(得分:6)

您被告知的问题很可能与在同一目录中堆积成千上万个文件的性能影响有关

要避免这种情况,请不要将文件直接存储在一个目录下,而是尝试将它们分散到子目录存储桶)下。

为了实现这一目标,请查看您要存储的文件的ID(比如19873),并将其存储在<uploads>/73/98/19873_<filename.ext>下,其中73是ID % 100,98是{{ 1}}等等。

以上保证(ID / 100) % 100下最多有100个子目录,<uploads>下最多有100个子目录。这将显着减少叶子上每个目录的文件数量。

两个级别的子目录足够典型,并且在不浪费太多时间将目录或文件名解析为广度上的inode之间表现出良好的平衡(当您在同一目录中查看太多文件名时会发生什么情况 - 尽管现代文件系统,如<uploads>/*在这里将非常有效)和深度(当你必须深入寻找你的文件的20个子目录时会发生什么)。您也可以选择使用更大或更小的值(10,1000)而不是100.使用模100的两个级别对于100k和5M文件之间是理想的

在给定需要检索的文件ID的情况下,使用相同的技术计算文件系统上文件的完整路径。

答案 1 :(得分:3)

您的第一个问题实际上取决于您使用的文件系统的类型。在回答时我会假设ext3没有任何日记优化。

首先,是的,当文件数量超过系统ARG_MAX时,一个地方的许多文件可能会导致问题。换句话说,rm -rf *会在抱怨太多参数时退出。您可以考虑使用指令A-Z / a-z并根据其唯一名称中最左侧字节的值适当地停放文件。

另外,尽量避免在短时间内打开所有这些文件的进程......一旦你真正开始填满,像'updatedb'这样的crons会引起问题。同样,尝试将这些目录保留在命令范围之外,例如'find'。

这导致另一个潜在的问题,缓冲。这些文件的访问频率是多少?如果给定目录中有300个文件,是否每30分钟至少访问一次?如果是这样,您可能需要打开/ proc / sys / vfs_cache_pressure设置,以便Linux将回收更多内存并使其可用于PHP / Apache / Etc。

最后,关于readfile ...我建议只使用直接下载链接。这避免了PHP在下载过程中必须保持活跃状态​​。

答案 2 :(得分:3)

  

此外,是否存在通过发送头信息和readfile()来强制下载的性能问题?

是的,如果你天真地这样做。一个好的文件下载脚本应该:

  • 流长文件以避免填充内存
  • 支持ETag和Last-Modified请求/响应标头以确保缓存继续工作
  • 提出合理的Expires / Cache-Control设置

它仍然不会像Web服务器那样快(通常用C语言编写并且针对服务文件进行了大量优化,甚至可能使用OS内核功能),但它会好得多。

  

保留文件名并允许直接下载使用不是使用脚本会更好吗?

它会表现得更好,是的,但获得正确的安全性是一项挑战。有关讨论,请参阅here

折衷方案是使用重写,以便URL看起来像:

hxxp://www.example.com/files/1234/Lovely_long_filename_that_can_contain_any_Unicode_character.zip

但它被内部重定向到:

hxxp://www.example.com/realfiles/1234.dat

并由网络服务器(快速)提供服务。

答案 3 :(得分:1)

如果您可能有数千个文件,则应将它们分布在许多子目录中。

我建议保留原始文件名,但您可能需要修改它以保证唯一性。这有助于诊断问题。

答案 4 :(得分:0)

我认为我建议使用一些脚本来控制滥用行为。此外,我建议保留文件名,除非您的脚本将在数据库上创建与其原始状态相关的索引。您还可以尝试使用一些Rewrite魔法来创建一个脚本,这样就可以通过不向最终用户公开背后的真实姓名(您的唯一ID)来提供另一层安全性。