【发布时间】:2010-10-11 10:22:39
【问题描述】:
我有一个简单的文件主机,它为文件提供一个唯一的 ID,并将它们存储在一个目录中。有人告诉我,这将在未来引起问题,我想知道我应该注意哪些事项以确保它在未来及以后顺利运行。
另外,通过发送标头信息和 readfile() 来强制下载是否存在性能问题?保留文件名并允许使用直接下载不是使用脚本会更好吗?
谢谢
【问题讨论】:
标签: php linux filesystems
我有一个简单的文件主机,它为文件提供一个唯一的 ID,并将它们存储在一个目录中。有人告诉我,这将在未来引起问题,我想知道我应该注意哪些事项以确保它在未来及以后顺利运行。
另外,通过发送标头信息和 readfile() 来强制下载是否存在性能问题?保留文件名并允许使用直接下载不是使用脚本会更好吗?
谢谢
【问题讨论】:
标签: php linux filesystems
我认为我建议使用一些脚本来控制滥用。另外我建议保留文件名,除非您的脚本将在数据库上创建与其原始状态相关的索引。您还可以尝试编写一个带有一些 Rewrite 魔法的脚本,这样可以通过不将背后的真实姓名(您的唯一 ID)暴露给最终用户来带来另一层安全性。
【讨论】:
您被告知的这类问题很可能与将成千上万个文件堆积在同一目录中对性能的影响有关。
为了避免这种情况,不要将文件直接存储在一个目录下,而是尝试将它们分散到子目录下(存储桶)。
为了实现这一点,请查看您要存储的文件的 ID(比如 19873),并将其存储在 <uploads>/73/98/19873_<filename.ext> 下,其中 73 是 ID % 100,98 是 (ID / 100) % 100 等。
以上保证<uploads> 下最多有100 个子目录,<uploads>/* 下最多还有100 个子目录。这将显着减少叶子中每个目录的文件数量。
两个级别的子目录已经足够典型了,并且代表了在不浪费太多时间将目录或文件名解析为 inode 之间的良好平衡(当您在同一个目录中有太多文件名需要查看时会发生这种情况 - 尽管现代文件系统,如ext3 在这里将非常有效)和深度(当你必须深入 20 个子目录来查找文件时会发生什么)。您也可以选择使用更大或更小的值(10、1000)而不是 100。模 100 的两个级别对于 100k 和 5M 之间的文件是理想的
在给定需要检索的文件 ID 的情况下,使用相同的技术来计算文件系统上文件的完整路径。
【讨论】:
您的第一个问题实际上取决于您使用的文件系统的类型。我会假设 ext3 在回答时没有任何日志优化。
首先,是的,当文件数量超过系统 ARG_MAX 时,一个位置的多个文件可能会导致问题。换句话说, rm -rf * 会在抱怨太多参数时退出。您可能会考虑使用目录 A-Z / a-z 并根据其唯一名称中最左侧字节的值适当地停放文件。
另外,尽量避免在短时间内打开所有这些文件的进程...一旦你真正开始填满,像“updatedb”这样的 cron 会导致问题。同样,尝试将这些目录排除在“find”等命令的范围之外。
这会导致另一个潜在问题,即缓冲区。这些文件的访问频率如何?如果给定目录中有 300 个文件,是否每 30 分钟至少访问一次?如果是这样,您可能需要调高 /proc/sys/vfs_cache_pressure 设置,以便 Linux 回收更多内存并使其可用于 PHP/Apache/Etc。
最后,关于 readfile ...我建议只使用直接下载链接。这避免了 PHP 在下载过程中必须保持活动状态。
【讨论】:
如果您可能有数千个文件,则应将它们分布在许多子目录中。
我建议保留原始文件名,但您可能需要修改它以保证唯一性。这有助于您诊断问题。
【讨论】:
另外,通过发送标头信息和 readfile() 强制下载是否存在性能问题?
是的,如果你天真地这样做。一个好的文件下载脚本应该:
它仍然不会像网络服务器那样快(通常用 C 语言编写并针对提供文件进行了高度优化,甚至可能使用操作系统内核功能),但它会好得多。
保留文件名并允许用户直接下载不是使用脚本会更好吗?
它会表现得更好,是的,但获得安全权利是一个挑战。请参阅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
并由网络服务器(快速)提供服务。
【讨论】: