缓存,PHP 生成的缩略图加载缓慢

问题 A 部分 (奖金100元)
主要问题是如何使这个网站,加载速度更快。首先我们需要解读这些瀑布。感谢您对瀑布读数分析的所有建议。从这里显示的各种瀑布图中可以明显看出主要的瓶颈: PHP 生成的缩略图。David 建议的从 CDN 加载无协议 jquery 获得了我的赏金,尽管总体上使我的站点只快了3% ,而且没有解决站点的主要瓶颈。是时候澄清我的问题了,还有,另一个奖励:

问题 B 部分 (奖金100元)
新的焦点是现在解决的问题,6 jpg 图像,这是造成大部分的加载延迟。这6张图片都是 PHP 生成的缩略图,很小,只有3 ~ 5kb,但是加载相对 非常比较慢。注意各种图表上的“ 到第一个字节的时间”。这个问题仍然没有得到解决,但是詹姆斯得到了一笔赏金,他修正了 RedBot 下划线: ”条件请求返回未改变的完整内容的头部错误。

问题 C 部分 (我最后的奖励: 250分)
不幸的是,甚至在修复了 REdbot.org 头部错误之后,PHP 生成的图像造成的延迟仍然没有改变。这些微不足道的3 ~ 5Kb 缩略图到底在想什么?所有这些头部信息可以把火箭送到月球再送回来。关于这个瓶颈问题的任何建议都受到高度赞赏,并被视为可能的答案,因为我已经被这个瓶颈问题困扰了七个月。

[我网站上的一些背景信息: CSS 在顶部。底部的 JS (JQuery,JQuery UI,购买了 menu awm/menu.JS 引擎,tab JS 引擎,video swfobject.JS)第二张图片上的黑线显示了什么引发了加载什么。愤怒的机器人是我的宠物“ ZAM”。他是无害的,而且常常很快乐。]


负荷瀑布: 时间顺序 | < a href = “ http://webpagetest.org”rel = “ nofollow noReferrer”> http://webpagetest.org enter image description here


并行域分组 | < a href = “ http://webpagetest.org”rel = “ nofollow norefrer”> http://webpagetest.org enter image description here


Site-Perf Waterfall | < a href = “ http://site-Perf.com”rel = “ nofollow norefrer”> http://Site-Perf.com enter image description here


Pingdom.com”rel = “ nofollow norefrer”> http://Tools.Pingdom.com

enter image description here


GTmetrix 瀑布 | < a href = “ http://GTmetrix.com”rel = “ nofollow norefrer”> http://GTmetrix.com

enter image description here


8333 次浏览

哇,很难用这个图像来解释事情. . 但是这里,有些尝试:

  • 文件33-36加载时间较晚,因为它们是在 swf 中动态加载的,而 swf (25)在加载任何其他内容之前首先完全加载
  • 文件20和21是由 all.js (11)加载的 也许吧(我不知道,因为我不知道你的代码)库,但是要执行11个文件,它需要等待整个页面(和资产)加载(你应该将其更改为 domready)
  • 文件22-32由这两个库加载,同样是在这两个库完全加载之后

只是一个简单的猜测,因为这种分析需要大量的 A/B 测试: 您的。Ch 域似乎很难到达(在第一个字节到达之前有很长的绿色带)。

这意味着。网站托管不善或你的 ISP 没有一个很好的路线到他们。

根据这些图表,这可以解释性能的巨大损失。

值得注意的是,有一个很酷的工具 巨大无比,它可以帮助您根据资源加载的顺序排序。

尝试在您的站点/页面上运行 Y! Slow 和 Page Speed 测试,并遵循指导方针来解决可能的性能瓶颈。一旦你在 Y 中得到更高的分数,你将获得巨大的性能提升。

这些测试会告诉你哪里出了问题,以及需要改变什么。

首先,使用这些多域需要多次 DNS 查找。您最好使用 把许多图像合成一个精灵而不是传播请求。

其次,当我加载页面时,我看到 all.js 上的大部分阻塞(~ 1.25 s)。我看到这是从(旧版本的) jQuery 开始的。您应该从 Google CDN 中引用它,不仅仅是 减少载入时间,而是整个 可能会避免对它的 HTTP 请求

具体来说,可以在这些 URL 上引用最新的 jQuery 和 jQuery UI 库(如果您对我为什么省略 http:感兴趣,请参阅 这篇文章) :

//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js


//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js

如果使用的是默认的 jQueryUI 主题之一,也可以使用 把它的 CSS 和图片从 Google CDN 上撤下来

对 jQuery 宿主进行了优化之后,还应该将 awmlib2.jstooltiplib.js组合成一个文件。

如果您解决了这些问题,您应该会看到一个显著的改进。

几天前我也遇到过类似的问题,我发现了 头 J。 这是一个 Javascript 插件,它允许你并行加载所有的 JS 文件。 希望能帮上忙。

所以你的 PHP 脚本正在生成每个页面加载的缩略图?首先,如果被缩略图显示的图像没有那么频繁地变化,那么您能否设置一个缓存,以便在每次加载页面时不必解析它们?其次,您的 PHP 脚本是否使用类似 imagecopyresampled()的东西来创建缩略图?这是一个非常重要的下行示例,PHP 脚本在完成收缩之前不会返回任何内容。使用 imagecopymerged()代替将降低图像的质量,但加速的过程。你减少了多少?这些缩略图是原始图像的5% 还是50% ?较大的原始图像可能会导致速度减慢,因为 PHP 脚本在缩小原始图像并输出较小的缩略图之前,必须在内存中获得原始图像。

我远不是专家,但是..。

关于这一点: ”条件请求返回未改变的完整内容 还有我的评论。

用于生成缩略图的代码应该检查以下内容:

  1. 是否有一个缓存版本的缩略图。
  2. 缓存的版本是否比原始图像新。

如果其中任何一个为 false,则无论如何都应该生成并返回缩略图。如果它们都是真实的,那么应该进行以下检查:

  1. 是否有 HTTP _ IF _ MODIFIED _ SINCE 头文件
  2. 缓存版本的最后修改时间与 HTTP _ IF _ MODIFIED _ SINCE 相同

如果其中任何一个为 false,则应返回缓存的缩略图。

如果这两个都是真的,那么应该返回一个304 http 状态。我不知道是否需要,但我也亲自返回缓存控制,过期和最后修改的标题连同304。

关于 GZip,我被告知没有必要使用 GZip 图片,所以忽略我评论中的那部分。

编辑: 我没有注意到你的文章增加了内容。

session_cache_limiter('public');
header("Content-type: " . $this->_mime);
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 2419200) . " GMT");
// I'm sure Last-Modified should be a static value. not dynamic as you have it here.
header("Last-Modified: " . gmdate("D, d M Y H:i:s",time() - 404800000) . " GMT");

我还确信您的代码需要检查 HTTP _ IF _ MODIFIED _ SINCE 头并对其作出反应。只要设置这些头和你的。Htaccess 文件不会提供所需的结果。

我觉得你需要这样的东西:

$date = 'D, d M Y H:i:s T'; // DATE_RFC850
$modified = filemtime($filename);
$expires = strtotime('1 year'); // 1 Year


header(sprintf('Cache-Control: %s, max-age=%s', 'public', $expires - time()));
header(sprintf('Expires: %s', date($date, $expires)));
header(sprintf('Last-Modified: %s', date($date, $modified)));
header(sprintf('Content-Type: %s', $mime));


if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
if(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified) {
header('HTTP/1.1 304 Not Modified', true, 304);
// Should have been an exit not a return. After sending the not modified http
// code, the script should end and return no content.
exit();
}
}
// Render image data

首先,您需要适当地处理 If-Modified-Since请求等,正如 James 所说。该错误指出: “当我询问服务器自上次以来是否修改了该映像时,它会发送整个映像,而不是简单的是/否”。

连接到第一个字节之间的时间通常是 PHP 脚本运行的时间。很明显,当该脚本开始运行时发生了一些事情。

  1. - 你有没有考虑过侧写?-可能会有些问题。
  2. 结合上述问题,您的脚本运行的次数可能比需要的次数多得多。理想情况下,它应该生成大拇指 除非的原始图像被修改,并发送缓存大拇指为每个其他请求。您是否检查过脚本是否在不必要地生成图像(例如,对于每个请求) ?

通过应用程序生成正确的头有点棘手,而且它们可能被服务器覆盖。任何发送一些无缓存请求标头的人都会导致缩略图生成器连续运行(并增加负载) ,这会使您暴露在滥用之下。因此,如果可能的话,尝试保存这些生成的拇指,直接从您的页面调用保存的图像,并管理来自 .htaccess的标题。在这种情况下,如果服务器配置正确,甚至不需要 .htaccess中的任何内容。

除此之外,您还可以应用 如何正确地做网站上这个漂亮的 SO 问题的性能部分中的一些明智的优化思想,比如将资源划分为无 cookie 的子域等等。但是无论如何,一个3k 图像不应该花费一秒钟来加载,这是显而易见的,当比较图表中的其他项目。在进行优化之前,您应该尝试发现问题。

调查 PHP 对会话数据的使用情况。也许(仅仅是也许) ,图像生成 PHP 脚本正在等待获得会话数据的锁,该数据被仍然呈现的主页或其他图像呈现脚本锁定。这将使所有的 JavaScript/浏览器优化几乎无关紧要,因为浏览器正在等待服务器。

PHP 为每个运行的脚本锁定会话数据,从会话处理开始,到脚本结束,或者调用 session _ write _ close ()。这有效地序列化了事物。查看关于会话的 PHP 页面,特别是注释,比如 这个

您是否尝试过在 NGINX 网络服务器下建立几个子域,专门用于服务图像和样式表等静态数据?一些有用的东西可能已经找到了 在这个话题中

我已经找到了您的网站的网址,并检查了个人的 jpg 文件从主页。 虽然现在加载时间是合理的(161毫秒) ,但等待126毫秒,这是太多了。

您最后修改的头部都设置为 Sat,01 Jan 201112:00:00 GMT,这看起来太“圆”,不是真正的生成日期; -)

由于 Cache-control 是“ public,max-age = 14515200”,任意最后修改的头在168天后可能会导致问题。

不管怎样,这不是延误的真正原因。

当缩略图已经存在时,您必须检查缩略图生成器执行什么操作,以及什么操作会占用如此多的时间来检查和传递图片。

您可以安装 Xdebug来分析脚本并查看瓶颈在哪里。

也许整个事情使用一个框架或连接到一些数据库免费。我在一些服务器上看到过非常慢的 mysql _ connect () ,主要是因为它们使用 TCP 而不是套接字进行连接,有时还有一些 DNS 问题。

我知道你不能把你的付费发电机寄到这里但恐怕有太多可能的问题..。

如果没有很好的理由(通常没有) ,那么您的映像就不应该调用 PHP 解释器。

为您的 Web 服务器创建一个重写规则,如果在文件系统中找到映像,该规则将直接服务该映像。如果不是,重定向到 PHP 脚本以生成图像。编辑图像时,更改图像文件名以强制拥有缓存版本的用户获取新编辑的图像。

如果它不工作,至少你现在将它没有任何关系的方式,图像创建和检查。

您是否尝试过将 PHP 生成的缩略图替换为常规图像,以查看是否有任何区别? 问题可能就在附近 - php 代码中的 bug 导致每次服务器调用时缩略图的再生 - 与时钟问题相关的代码延迟(sleep () ?) 一个硬盘问题导致一个非常糟糕的比赛条件,因为所有的缩略图被加载/生成在同一时间。

关于延迟的缩略图,尝试在缩略图生成脚本中最后一次调用 Header ()之后立即调用 冲水。完成之后,重新生成瀑布图,看看延迟现在是否在主体上而不是标题上。如果是这样,那么您需要仔细研究生成和/或输出图像数据的逻辑。

处理缩略图的脚本应该使用某种类型的缓存,这样它对您提供的图像所采取的任何操作只会在绝对必要的时候才会发生。看起来每次提供缩略图时都会发生一些昂贵的操作,这会延迟脚本中的 任何输出(包括头部)。

我认为,与其使用 缩略图生成器脚本缩略图生成器脚本,你必须给 TinySRC一个快速快速和云托管缩略图生成的尝试。 它有一个非常简单和易于使用的 API,你可以像这样使用:-

Http://i.tinysrc.mobi/ http://domain.tld/path_to_img.jpg

[ width ] (可选) :- 这是一个以像素为单位的宽度(它覆盖了自适应或系列大小调整)。如果前缀为“-”或“ x”,它将减去或缩小到所确定大小的百分比。

[身高] (可选) :- 这是一个以像素为单位的高度,如果宽度也存在的话。它还可以覆盖自适应或家庭规模,并且可以以“-”或“ x”作为前缀。

您可以检查 API 摘要 给你


常见问题

TinySrc 花了我多少钱?

没什么。

我什么时候可以开始使用 tinySrc?

现在。

服务可靠吗?

我们不能保证 tinySrc 服务。然而,它运行在一个 abc0上,因此它提供全球高可用性。它应该足以满足你所有的需要。

它有多快?

TinySrc 将调整大小的图像缓存在内存和我们的数据存储中长达24小时 ,并且它不会每次都获取原始图像。这使得服务从用户的角度看成为 极快的速度。(并减少服务器负载作为一个很好的副作用。)


祝你好运,这只是个建议,因为你没有给我们展示密码

这只是一个大胆的猜测,因为我还没有看过你的代码,但我怀疑会话可能在这里发挥了作用,以下是来自 session_write_close()的 PHP 手册条目:

会话数据通常存储在 你的脚本终止了 需要调用 session _ write _ close () , 但是当会话数据被锁定到 防止并发写入只有一个 脚本可以在任何 当一起使用框架集时 你会体验到 由于这个原因,帧一个接一个地加载 锁定。 你可以减少时间 需要加载所有的帧 尽快结束会议 会话变量的更改如下 完成

就像我说的,我不知道你的代码在做什么但是这些图表看起来很奇怪。我有一个类似的问题时,我编写了一个多部分文件服务函数和我有同样的问题。当服务一个大文件时,我不能让多部分功能工作,也不能打开另一个页面,直到下载完成。我的两个问题。

很遗憾地说,您提供的数据很少,而且您已经有了一些很好的建议。

你是怎么处理这些图像的?如果您使用 PHP 来传输这些内容,那么即使已经生成了这些内容,您也是在做一件非常糟糕的事情。

切勿使用 PHP 进行图像流处理。无论你使用什么方式,它都会降低服务器的速度。

把他们放在一个可访问的文件夹,有一个有意义的 URI。然后直接调用他们的真正的 URI。 如果您需要在飞行代,您应该放置一个。Htaccess 在图像目录中,只有当请求图像丢失时才会重定向到生成器 php-script。(这被称为缓存请求策略)。

这样做可以同时修复 php 会话、浏览器代理、缓存、 ETAGS 等所有问题。

如果配置正确,WP-Superache 使用这种策略。

我写这一段时间以前(http://code.google.com/p/cache-on-request/source/detail?r=8) ,最后的修订是破碎的,但我想8或更少应该工作,你可以抓住。以 htaccess 为例进行测试(尽管有更好的方法来配置。Htaccess 比我以前的访问方式)。

我在这篇博客文章(http://www.stefanoforenza.com/need-for-cache/)中描述了这种策略。它可能写得很糟糕,但它可能有助于澄清事情。

延伸阅读: http://meta.wikimedia.org/wiki/404_handler_caching

由于一些浏览器每个域只下载2个并行下载,你能不能通过两到三个不同的主机名向 分割请求添加额外的域名。例如1.imagecdn.com 2。Imagecdn.com

大多数慢的问题是你的 TTFB (时间到第一个字节)太高。如果不熟悉服务器配置文件、代码和底层硬件,这是一个很难解决的问题,但我可以看到它在每个请求中都很猖獗。你有太多的绿色条(坏)和很少的蓝色条(好)。你可能想停止优化前端一点,因为我相信你已经做了很多这方面的工作。尽管有句谚语“ 80% -90% 的最终用户响应时间花费在前端”,我相信你的故事发生在后台。

TTFB 是后端的东西,服务器的东西,预处理之前的输出和握手。

计算代码执行的时间,以找到缓慢的东西,如缓慢的数据库查询,进入和退出函数/方法的时间,以找到缓慢的函数。如果使用 php,请尝试 菲尔普。有时,在启动或初始化过程中会运行一两个缓慢的查询,比如提取会话信息或检查身份验证等等。优化查询可以获得一些很好的性能收益。有时候代码是使用 php prepend 或 spl autoload 运行的,所以它们可以运行在任何地方。其他时候,它可以错误地配置 apache conf 和调整,以节省一天。

寻找低效循环。查找由于磁盘驱动器故障或磁盘空间使用率高而导致的缓存缓存获取调用或输入输出操作缓慢。查找内存使用情况以及正在使用的内存和位置。运行网页测试重复测试10个运行在一个图像或文件,只使用第一次查看来自世界各地的不同位置,而不是相同的位置。并阅读您的访问和错误日志,太多的开发人员忽视它们,只依赖于屏幕上输出的错误。如果你的主机得到了支持,向他们寻求帮助,如果他们不能礼貌地向他们寻求帮助,也不会有什么坏处。

您可以尝试 DNS 预取来对抗许多域和资源,http://html5boilerplate.com/docs/DNS-Prefetching/

你自己的服务器是一个好的/像样的服务器吗?有时一个更好的服务器可以解决很多问题。我是一个“ 硬件很便宜,程序员很贵”心态的球迷,如果你有机会和金钱升级服务器。和/或使用类似 Maxcdn云烟或类似的 CDN。

祝你好运!

另外,我不为这些公司工作。另外,上面的 Cloudflare 链接会说 TTFB 并不那么重要,我把它放在那里,这样你就可以得到另一个镜头。)