我希望我能更具体地说明这个问题,并且我真的想寻求关于下一步该怎么做的建议。
我们正在运行一个与 WordPress 集成的 PHP Web 应用程序,该应用程序在一天中的某些时段每秒提供一个页面。通常,在单个专用服务器(四核,16GB RAM)上运行良好。
我正在考虑 New Relic,他们的工具提醒我偶尔的页面加载,其中 PHP 似乎停滞了。它在调用跟踪中到达一个看似任意的点,然后在一些琐碎的事情上花费了很多秒(或几十秒)。最简单的例子是一个条件函数,后面跟着 echo()。
我看不到与这些事件同时发生的任何其他错误(在 Apache/PHP 错误日志中)或慢速查询。它们似乎也没有与任何特别重的 CPU 负载、磁盘 I/O 或网络 I/O 同时发生。
这种情况每小时会发生几次,所有停滞的函数都有一个共同点,那就是它们正在向页面输出。是否有东西阻塞了输出缓冲区?或者是否有其他明显的罪魁祸首可能导致此问题?您接下来会做什么来排除故障?
Linux:CentOS 5.6
阿帕奇:2.2.3
MYSQL:5.5
PHP:5.3.9
APC:3.1.9(缓存健康,命中率接近100%)
答案1
PHP FPM SAPI 有一个慢日志,其中脚本运行时间超过n秒可以使用回溯记录。遗憾的是,没有其他 SAPI 具有此功能。(如果您已经在使用 nginx+PHP-FPM,那么您已经拥有此功能!它不止一次救了我一命。)
后备方案似乎是运行 xdebug,但这在生产环境中可能会变得棘手。或者更糟的是,使用自己的“调试”脚本(请参阅 Stack Overflow 上的这个问题,了解不好的例子)。
答案2
正如 JakeGould 所说,这是一个配置问题。
解决方案是将最大 TCP/IP 写入缓冲区大小提高到 256k(之前约为 128k),并使用 httpd.conf 中 prefork 模块中的 SendBufferSize 指令指定 Apache 使用最大值。如果您使用 prefork 作为 MPM,则这适用于您。其他 MPM 可能有所不同。
解决这个问题的原因是:
我们有时会提供较大的页面,当页面大小大于发送缓冲区时,Apache 会在缓冲区已满时发送该缓冲区,然后等待客户端的响应再发送其余部分。即使在网络连接良好的情况下,这也会导致一两秒的延迟,如果网络连接不佳,情况会更糟。我认为对于真正病态的情况(达到 120 秒的限制),用户会在几秒钟后沮丧地离开页面,因此服务器永远不会得到响应。
通过将发送缓冲区设置为大于大多数页面的大小,Apache 会发送完整页面并且不等待响应。
当然,这同样适用于您提供的单个图像。如果它们大于发送缓冲区,那么您就会遇到此问题。我们的大多数图像都由 CDN 提供,但一些不在 CDN 上的大图像会触发此问题。
虽然这对与我们的网站连接较差的客户端没有太大帮助,但它将我们的平均响应时间从 200 毫秒以上缩短到了 100 毫秒以下。此外,通过清除所有这些缓慢的事务,我现在可以在剩余的事务中看到真正的性能问题。