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

时间:2011-01-26 22:29:10

标签: php performance .htaccess cache-control

问题A部分▉(100个赏金,获奖)
主要问题是如何使这个网站,加载更快。首先,我们需要阅读这些瀑布。感谢您对瀑布读数分析的建议。从这里显示的各种瀑布图表可以看出主要的瓶颈:PHP生成的缩略图。来自CDN建议的无协议jquery加载获得了我的赏金,虽然使我的网站总体上只增加了3%,​​并且没有回答网站的主要瓶颈。是时候澄清我的问题,还有另一个赏金:

问题B部分▉(100个赏金,获奖)
现在新的焦点是解决6 jpg图像所带来的问题,这些问题导致了大部分的加载延迟。这6个图像是PHP生成的缩略图,很小,只有3~5 kb,但相对非常缓慢加载。请注意各种图表上的“第一个字节的时间”。这个问题仍未得到解决,但詹姆斯获得了一笔赏金,他修复了RedBot underlined的标题错误:“If-Modified-Since条件请求返回了完整内容不变。”。< / p>

问题C部分▉(我最后的赏金:250分)
不幸的是,在修复了REdbot.org标头错误之后,由PHP生成的图像引起的延迟仍未受到影响。这些微小的3~5Kb缩略图在想什么呢?所有标题信息都可以发送火箭到月球和后面。关于这个瓶颈的任何建议都非常受欢迎并被视为可能的答案,因为我已经困在这个瓶颈问题已经七个月了。我提前感谢。

[我网站上的一些背景信息:CSS位于顶部。 JS底部(Jquery,JQuery UI,购买菜单awm / menu.js引擎,标签js引擎,视频swfobject.js)第二个图像上的黑线显示什么是启动加载的内容。愤怒的机器人是我的宠物“ZAM”。他是无害的,往往更快乐。]


加载瀑布:按时间顺序 | http://webpagetest.org enter image description here


并行域名分组 | http://webpagetest.org enter image description here


Site-Perf瀑布 | http://site-perf.com enter image description here


Pingdom工具瀑布 | http://tools.pingdom.com

enter image description here


GTmetrix瀑布 | http://gtmetrix.com

enter image description here


19 个答案:

答案 0 :(得分:61)

首先,使用这些多个域需要多次DNS查找。你最好离开combining many of those images into a sprite而不是传播请求。

其次,当我加载你的页面时,我看到all.js上的大部分阻塞(~1.25s)。我看到它以jQuery的旧版本开头。您应该从Google CDN中引用该内容,而不仅仅是decrease load time,而是potentially avoid an HTTP request for it

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

//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

如果您使用的是默认的jQuery UI主题之一,您还可以pull its CSS and images off the Google CDN

通过优化jQuery托管,您还应该将awmlib2.jstooltiplib.js合并到一个文件中。

如果您解决这些问题,您应该会看到显着的进步。

答案 1 :(得分:17)

几天前我遇到过类似的问题。我找到了head.js。 它是一个Javascript插件,允许您加载所有JS文件并行。 希望有所帮助。

答案 2 :(得分:12)

我远非专家,但......

关于这个问题: “If-Modified-Since条件请求返回完整内容不变。” 和我的评论。

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

  1. 是否有缩略图的缓存版本。
  2. 缓存版本是否比原始图像更新。
  3. 如果其中任何一个为假,则无论如何都应生成并返回缩略图。如果它们都是真的那么应该进行以下检查:

    1. 是否有HTTP_IF_MODIFIED_SINCE标头
    2. 缓存版本的上次修改时间是否与HTTP_IF_MODIFIED_SINCE相同
    3. 如果其中任何一个为false,则应返回缓存的缩略图。

      如果两者都为真,则应返回304 http状态。我不确定它是否需要,但我也亲自返回Cache-Control,Expires和Last-Modified标头以及304。

      关于GZipping,我被告知不需要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
      

答案 3 :(得分:6)

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

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

答案 4 :(得分:4)

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

这意味着.ch网站托管不当或您的ISP没有良好的路由。

鉴于图表,这可以解释一个重大的性能影响。

另外,有一个很酷的工具cuzillion可以帮助您根据资源加载的顺序进行排序。

答案 5 :(得分:4)

尝试在您的网站/页面上运行Y!Slow和Page Speed测试,并按照指南排列可能的性能瓶颈。一旦你在Y!Slow或Page Speed中得分更高,你应该获得巨大的性能提升。

这些测试会告诉你哪些错误以及要改变什么。

答案 6 :(得分:4)

那么你的PHP脚本是否在每个页面加载时生成缩略图?首先,如果正在缩略图像不经常更改,您是否可以设置缓存,以便每次页面加载时都不必解析它们?其次,您的PHP脚本是否使用imagecopyresampled()之类的东西来创建缩略图?这是一个非平凡的缩减示例,PHP脚本在完成收缩之前不会返回任何内容。使用imagecopymerged()会降低图像质量,但会加快处理速度。你做了多少减少?这些缩略图的大小是原始图像的5%还是50%?原始图像的较大尺寸可能导致速度减慢,因为PHP脚本必须先将内存中的原始图像缩小并输出较小的缩略图。

答案 7 :(得分:4)

我找到了您网站的网址,并在主页上查看了单个jpg文件。 现在加载时间合理(161ms),它等待126ms,这太过分了。

您最近修改过的标题都设置为星期六,2011年1月1日12:00:00格林尼治标准时间,它看起来太“圆”而不是生成的真实日期; - )

由于缓存控制是“public,max-age = 14515200”,因此任意最后修改的标题可能会在168天后导致问题。

无论如何,这不是延误的真正原因。

当缩略图已经存在时,你必须检查你的缩略图生成器做了什么,以及检查和传送图片会花费多少时间。

您可以安装xdebug来分析脚本并查看瓶颈所在。

也许整个事情都使用框架或连接到某个数据库。我在一些服务器上看到了非常慢的mysql_connect(),主要是因为它们使用TCP连接而不是套接字,有时会出现一些DNS问题。

我知道你不能在这里发布你的付费发电机,但我担心会有太多可能的问题......

答案 8 :(得分:4)

如果没有一个非常好的理由(通常没有),你的图像不应该调用PHP解释器。

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

如果它至少不起作用,那么现在它与创建和检查图像的方式没有任何关系。

答案 9 :(得分:3)

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

PHP会锁定运行的每个脚本的会话数据,从会话处理开始的那一刻起,到脚本完成的那一刻,或者调用session_write_close()的时刻。这有效地序列化了事物。查看会话的PHP页面,尤其是评论,例如this one

答案 10 :(得分:3)

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

  

会话数据通常存储在之后   你的脚本终止没有   需要调用session_write_close(),   但是会话数据被锁定   防止并发写入只有一个   脚本可以在任何会话上运行   时间。一起使用框架集时   通过会议,您将体验到   由于这个原因逐帧加载   锁定。 您可以减少时间   需要加载所有帧   所有人都尽快结束会议   对会话变量的更改是   完成。

就像我说的那样,我不知道你的代码在做什么,但这些图形看起来很奇怪。 I coded a multipart file serving function时我遇到了类似的问题,我遇到了同样的问题。当提供大文件时,我无法使多部分功能工作,也无法在下载完成之前打开另一个页面。 Calling session_write_close() fixed我的问题。

答案 11 :(得分:2)

由于某些浏览器每个域只下载2个并行下载,您是否可以通过两到三个不同的主机名向shard the requests添加其他域名。例如1.imagecdn.com 2.imagecdn.com

答案 12 :(得分:2)

您是否尝试过常规图像替换php生成的thumnails,看看是否有任何区别? 问题可能存在    - 您的PHP代码中的错误导致每次服务器调用时缩略图的重新生成    - 与时钟问题相关的代码延迟(sleep()?)    - 由于所有缩略图同时被加载/生成,因此导致非常糟糕的竞争条件的硬盘问题。

答案 13 :(得分:2)

我认为不是使用缩略图 - 生成器脚本,而是必须尝试TinySRC快速生成快速和云托管的缩略图。 它有一个非常简单易用的API,您可以使用如下: -

http://i.tinysrc.mobi/ [身高] / [宽度] /http://domain.tld/path_to_img.jpg

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

[身高] (可选): - 如果宽度也存在,则这是以像素为单位的高度。它还会覆盖自适应或大小调整,并且可以使用' - '或'x'作为前缀。

您可以查看API摘要here


FAQ

tinySrc花了我多少钱?

没有

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

现在

该服务的可靠性如何?

我们不保证tinySrc服务。但是,它运行在主要的分布式云基础架构上,因此它在全球范围内提供高可用性。它应该足以满足您的所有需求。

速度有多快?

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


祝你好运。只是一个建议,因为你没有向我们展示代码:p

答案 14 :(得分:1)

大多数缓慢的问题是你的TTFB(第一个字节的时间)过高。如果不与您的服务器配置文件,代码和底层硬件保持密切关系,这是一个很难解决的问题,但我可以看到它在每个请求上都很猖獗。你有太多绿色条(坏)和非常小的蓝色条(好)。您可能希望停止优化前端,因为我相信您已经在该领域做了很多工作。尽管有“80%-90% of the end-user response time is spent on the frontend”的格言,但我相信你的后端正在发生。

TTFB是后端内容,服务器内容,输出前的预处理和握手。

计算代码执行的时间,以找到缓慢的数据库查询,进入和退出函数/方法以查找慢速函数等慢速内容。如果您使用php,请尝试Firephp。有时,在启动或初始化期间运行一两个慢查询,例如拉取会话信息或检查身份验证,什么不是。优化查询可以带来一些良好的性能提升。有时代码是使用php prepend或spl autoload运行的,所以它们可以在所有内容上运行。其他时候,它可能是错误配置apache conf和调整,节省了一天。

寻找效率低下的循环。查找由于磁盘驱动器故障或磁盘空间使用率过高而导致缓存的缓慢调用或缓慢的I / O操作。寻找内存使用情况以及使用的内容和位置。仅使用来自世界各地的不同位置的第一个视图而不是相同的位置,对单个图像或文件运行10次运行的网页测试重复测试。并且读取您的访问和错误日​​志,太多开发人员忽略它们并仅依赖输出的屏幕错误。如果您的网站主机有支持,请向他们寻求帮助,如果他们不礼貌地请求他们寻求帮助,也不会受到伤害。

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

服务器是你自己的好/好的服务器吗?有时一个更好的服务器可以解决很多问题。如果你有机会和钱升级服务器,我就是'hardware is cheap, programmers are expensive'心态的粉丝。和/或使用像maxcdncloudflare或类似的CDN。

祝你好运!

(p.s。我不适用于任何这些公司。而且上面的cloudflare链接会说TTFB并不重要,我把它扔在那里,这样你就可以再拿一次。)

答案 15 :(得分:1)

关于延迟缩略图,请在缩略图生成脚本中最后一次调用flush()后立即拨打header()。完成后,重新生成瀑布图并查看延迟是否在身体上而不是标题上。如果需要,您需要仔细查看生成和/或输出图像数据的逻辑。

处理缩略图的脚本应该有希望使用某种缓存,这样无论对你所服务的图像采取的任何操作都只会在绝对必要时才会发生。看起来每次提供缩略图时都会进行一些昂贵的操作,这会延迟脚本中任何输出(包括标题)。

答案 16 :(得分:1)

您是否尝试在NGINX webserver下设置多个子域,专门用于提供图像和样式表等静态数据?可以找到有用的东西in this topic

答案 17 :(得分:1)

首先,正如詹姆斯所说,你需要妥善处理If-Modified-Since个请求。该错误表明:“当我询问您的服务器自上次以来是否修改了该图像时,它会发送整个图像而不是简单的是/否”。

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

  1. 你考虑过分析它吗?它可能有一些问题。
  2. 结合上述问题,您的脚本可能运行的次数超过了所需的次数。理想情况下,只有在原始图像被修改时才应生成拇指,并为每个其他请求发送缓存的拇指。您是否检查过脚本是否不必要地生成图像(例如,对于每个请求)?
  3. 通过应用程序生成正确的标头有点棘手,而且它们可能会被服务器覆盖。并且您会受到滥用,因为任何发送一些无缓存请求标头的人都会导致缩略图生成器连续运行(并提高负载)。因此,如果可能,请尝试保存生成的拇指,直接从您的网页调用已保存的图像,并从.htaccess管理标题。在这种情况下,如果您的服务器配置正确,您甚至不需要.htaccess中的任何内容。

    除了这些之外,您可以在how to do websites the right way上应用这个整体优秀SO问题的性能部分中的一些明亮的优化想法,比如将您的资源分成无cookie子域等等。但无论如何,一个3k图像不应该花费一秒钟加载,与图表中的其他项目相比,这是显而易见的。您应该在优化之前尝试发现问题。

答案 18 :(得分:-1)

很抱歉,您提供的数据很少。你已经有了一些很好的建议。

你是如何为这些图像提供服务的?如果你通过PHP流式传输它们,那么即使它们已经生成,你也会做一件坏事。

从不使用PHP流式传输图像。无论您使用它的方式如何,它都会降低您的服务器速度。

将它们放在具有有意义URI的可访问文件夹中。然后用他们真正的URI直接调用它们。 如果你需要动态生成,你应该在images目录中放置.htaccess,只有在缺少请求图像时才会重定向到生成器php脚本。 (这称为缓存请求策略)。

这样做会修复php会话,浏览器代理,缓存,ETAGS等等。

如果配置正确,WP-Supercache会使用此策略。

我前段时间写过这篇文章(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