当在LAMP服务器上有数百万用户时,最快和最有效的存储和提取图像的方法是什么?

7
以下是我目前想到的最佳方法,希望知道是否有更好的方法(肯定有!)来存储和获取数百万个用户图像:
为了保持目录大小并避免进行任何额外的数据库调用,我使用基于用户唯一ID计算的嵌套目录,如下所示:
$firstDir = './images';
$secondDir = floor($userID / 100000);
$thirdDir = floor(substr($id, -5, 5) / 100);
$fourthDir = $userID;
$imgLocation = "$firstDir/$secondDir/$thirdDir/$fourthDir/1.jpg";

用户ID($userID)的范围从1到数百万。

举例来说,如果我的用户ID是7654321,那么这个用户的第一张图片将被存储在:

./images/76/543/7654321/1.jpg

对于用户ID为654321

./images/6/543/654321/1.jpg

对于用户ID 54321,它应该是:

./images/0/543/54321/1.jpg

对于用户ID 4321,它应该是:

./images/0/43/4321/1.jpg

对于用户ID 321,它应该是:

./images/0/3/321/1.jpg

对于用户ID 21,它应该是:

./images/0/0/21/1.jpg

对于用户ID 1,它将是:

./images/0/0/1/1.jpg

这样可以确保即使有1亿用户,也不会出现超过1000个子目录的情况,因此似乎可以保持目录的整洁和高效。
我将这种方法与使用以下“哈希”方法进行了基准测试,该方法使用PHP中最快的哈希方法(crc32)。该“哈希”方法计算第二个目录为用户ID哈希的前3个字符,将第三个目录计算为接下来的3个字符,以便按顺序随机但均匀地分配文件,如下所示:
$hash = crc32($userID);
$firstDir = './images';
$secondDir = substr($hash,0,3);
$thirdDir = substr($hash,3,3);
$fourthDir = $userID;
$imgLocation = "$firstDir/$secondDir/$thirdDir/$fourthDir/1.jpg";

然而,这种“哈希”方法比我之前描述的方法慢,因此并不好。接着,我走了一步 further,找到了一个更快的方法来计算我原始例子中的第三个目录(floor(substr($userID, -5, 5) / 100);),具体方法如下:
$thirdDir = floor(substr($userID, -5, 3));

现在,这改变了前10000个用户ID存储的方式/位置,使一些第三方目录只有1个用户子目录或111个用户子目录,而不是100个,但它具有更快的速度,因为我们不必除以100,所以我认为从长远来看这是值得的。

一旦目录结构被定义,以下是我计划如何存储实际的单个图像:例如,如果用户上传第二张图片,它将放置在与他们的第一张图片相同的目录中,但它的名称将是2.jpg。 用户的默认图片总是1.jpg,因此如果他们决定将第二张图片设置为默认图片,则2.jpg将重命名为1.jpg,并且1.jpg将被重命名为2.jpg

最后但并非最不重要的是,如果我需要存储同一图像的多个尺寸,则会按以下方式为用户ID 1进行存储:

1024px:

./images/0/0/1/1024/1.jpg
./images/0/0/1/1024/2.jpg

640像素:

./images/0/0/1/640/1.jpg
./images/0/0/1/640/2.jpg

就是这样。

那么,这种方法有什么缺陷吗?如果有的话,请指出来。

有没有更好的方法?如果有的话,请描述一下。

在我开始实现它之前,我想确保我拥有最佳、最快和最有效的存储和检索图像的方法,这样我就不必再次更改它。

谢谢!


1
我真的希望你存储/访问的内容不是私人或机密的,因为这样很容易浏览到其他用户的图像文件夹。 - Joel C
隐私在我的情况下不是问题,所以这不应该成为一个问题。我的用户希望他们的照片被看到。为了全面考虑,如果隐私是一个问题,你会推荐什么解决方案? - ProgrammerGirl
1
加载数百万张图片的最快方法是“不要加载它们”。也就是说,使用memcached,并依赖于这样一个假设:95%的用户大部分时间都想看到同样的5%的图片。 - Damon
1个回答

3
不必担心计算路径的微小差异,这不重要。重要的是如何在目录中均匀分配图像,生成的路径有多短,以及推断命名约定的难度(我们将1.jpg替换为2.jpg..哇,它起作用了..)。
例如,在您的哈希解决方案中,路径完全基于用户ID,这将使所有属于一个用户的图片放置在同一个目录中。
使用整个字母表(大写和小写字母,如果您的文件系统支持),而不仅仅是数字。检查其他软件的做法,一个检查哈希目录名称的好地方是Google Chrome,Mozilla等等。最好使用较短的目录名称。更快查找,占用HTML文档中的空间更少。

但是,一旦有数百万用户同时与服务器交互,那么这些微小的速度差异/所需的CPU将会被显著放大,不是吗? - ProgrammerGirl
@程序员,如果这么小的效率差异使您的网站无法使用,那您应该使用服务器群来扩展您的网站。除了效率之外,还有更大更重要的问题,比如安全性。执行安全检查并不“高效”,但如果您失去了所有用户,页面加载速度多快也无关紧要。如果您真的有数百万用户而又负担不起服务器群,那么您可能需要重新思考您的商业模式。 - Joel C
取决于你如何定义“严重的缺点”,我想。总是有权衡,开发人员/系统架构师的工作就是平衡这些权衡。如果你真的想要最高效率的水平,为什么要用PHP编写你的网站?使用汇编语言,它更有效率。 - Joel C
没有缺点吗?images/76/543/7654321/101.jpg 可以变成 i/a7/c3/5e.jpg,这样的话文件大小不到原来的一半。 - Karoly Horvath
@Joel C:但我是指我的帖子背景。你是否在说所提及的方法相较于更好的方法有严重的缺陷? - ProgrammerGirl
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接