我在 Apache 2.2 服务器(Ubuntu Server 10.04、8x2GHz、12Gb RAM)上运行 PHP Web 应用程序prefork
。Apache 每天收到大约 100k-200k 个请求,其中大约 100-200 个达到超时限制(大约每千个请求中有一个),几乎所有其他请求都在超时之前得到处理。
我该怎么做才能找出发生这种情况的原因?或者所有请求中都有一小部分超时是正常的吗?
这是我目前所做的:
可以看出,很少有请求介于超时限制和更合理的请求之间。当前超时限制设置为 50 秒,之前设置为 300 秒,情况仍然相同,有些请求超时,然后与其他请求的差距很大。
所有超时的请求都是AJAX
请求,但绝大多数都是请求,所以也许这更像是巧合。Apache 返回代码是200
,但显然已达到超时限制。它们来自各种不同的 IP。
我查看了超时的请求,它们没有什么特殊之处,如果我执行相同的请求,它们会在不到 1 秒的时间内完成。
我尝试查看不同的资源,看看能否找到原因,但没有成功。总是有足够的可用内存(最低约 3GB),负载有时会高达 1.4,CPU 利用率达到 40%,但许多超时发生在负载和 CPU 利用率较低时。磁盘写入/读取在一天中几乎是恒定的。MySQL 慢查询日志中没有条目(设置为记录超过 1 秒的任何内容),没有请求使用那么多数据库写入/读取。
蓝色表示 CPU 利用率,峰值为 40%,栗色表示负载,峰值为 1.4。因此,我们可以看到,即使 CPU 利用率/负载较低,也会出现超时(十秒的峰值与 CPU 利用率非常吻合,但那是另一个问题,我更希望能找出导致这些情况的原因)。
Apache 错误日志中没有错误,而且我也没有看到它达到超过 200 个活动的 Apache 进程。
服务器设置:
Timeout 50
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 2
<IfModule mpm_prefork_module>
ServerLimit 350
StartServers 20
MinSpareServers 75
MaxSpareServers 150
MaxClients 320
MaxRequestsPerChild 5000
</IfModule>
更新:
我更新到了 Ubuntu 12.04.1,以防万一,没有变化。我添加了 mod_reqtimeout 并设置如下:
RequestReadTimeout header=20-40,minrate=500
RequestReadTimeout body=10,minrate=500
现在几乎所有超时都发生在 10 秒,一两次发生在 20 秒。我认为这意味着大多数时候获取请求主体时会出现问题?请求主体不应大于几百字节。我以每秒为单位监控网络流量,它从未高于 1Mbit/s,而且我没有看到任何 rxerrs 或 rxdorps,考虑到服务器在 1Gbit/s 的线路上,这听起来不像 HopelessN00b 发布的那样。可能只是一些用户连接不良的情况?
对于每小时的峰值(它们似乎有点漂移,在上面的图表中它们出现在每小时 33 分钟后,现在它们出现在每小时 12 分钟后),我尝试查看是否有任何定期运行的程序(crons 等),但一无所获。PHP 垃圾收集每小时运行两次,但不是在峰值时运行,我仍然尝试禁用它,但没有任何区别。
我使用带有 --top-cpu 和 top 的 dstat 查看了峰值时的进程,显示的只是 apache 努力工作了几秒钟,但没有其他进程正在使用大量 CPU。
我制作了一张放大的峰值图:
在我看来,Apache 似乎暂停了几秒钟,然后努力处理暂停期间收到的请求。什么可能导致这种暂停,还是我误解了?
答案1
我注意到的第一件事是,看你的第一张图表,似乎每小时都会出现一次减速(大约在整点后 40 分钟),这可能是导致问题的原因。你应该看看操作系统/数据库上的任务调度程序。
根据您提供的数据,我的下一步是查看响应时间的频率(Y 轴上的响应次数与 X 轴上的持续时间),但只包括显示超时的 URL(或最好一次一个 URL)。在典型的系统中,这应该遵循正态分布或泊松分布 - 超时的请求可能只是尾部的一部分 - 在这种情况下,您需要将精力集中在一般调整上。另一方面,如果分布是双峰的,那么您需要在代码中的某个地方寻找争用。
答案2
我对此有另一种想法,基于这样一个事实:您每天都会收到大量请求,并且似乎只有在高峰时段才会超时(从您发布的图片来看)。
Server Fault 博客上有一篇文章,Per Second Measurements Don't Cut It
... 这些请求中的一些是否可能遇到与 ServerFault 团队遇到的相同问题?
我们发现,在 1 Gbit/s 接口上,我们经常以 10-30 MBit/s 的速率丢弃数据包,这损害了我们的性能。这是因为 10-30 MBit/s 的速率实际上是每 5 分钟传输的位数,转换为一秒的速率。当我们使用 Wireshark 进行深入研究并使用一毫秒 IO 图形时,我们发现所谓的 1 Gbit/s 接口会频繁地突破 1 Mbit/ms 的速率。