高负载 Apache 服务器的性能调优

高负载 Apache 服务器的性能调优

我想了解一些我遇到的(对我们来说)负载过重的 Web 服务器的性能问题。环境如下:

  • Debian Lenny(所有稳定软件包 + 修补安全更新)
  • Apache 2.2.9
  • PHP 5.2.6
  • Amazon EC2 大型实例

我们看到的行为是,Web 通常感觉响应迅速,但开始处理请求时会稍有延迟 —— 有时是几分之一秒,有时在高峰使用时间是 2-3 秒。服务器上的实际负载被报告为非常高 —— 通常为 10.xx 或 20.xx(如 报告的那样)top。此外,在这些时间(甚至 )在服务器上运行其他程序vi非常慢,因此负载肯定很高。奇怪的是,除了最初的延迟之外,Apache 仍然非常灵敏。

我们使用 prefork 对 Apache 进行如下配置:

StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0

并将 KeepAlive 设置为:

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

查看服务器状态页面,即使在负载很重的时候,我们也很少达到客户端上限,通常处理 80-100 个请求,其中许多请求处于保持活动状态。这告诉我可以将初始请求缓慢排除为“等待处理程序”,但我可能错了。

亚马逊的 CloudWatch 监控告诉我,即使我们的操作系统报告负载 > 15,我们的实例 CPU 利用率也在 75-80% 之间。

示例输出来自top

top - 15:47:06 up 31 days,  1:38,  8 users,  load average: 11.46, 7.10, 6.56
Tasks: 221 total,  28 running, 193 sleeping,   0 stopped,   0 zombie
Cpu(s): 66.9%us, 22.1%sy,  0.0%ni,  2.6%id,  3.1%wa,  0.0%hi,  0.7%si,  4.5%st
Mem:   7871900k total,  7850624k used,    21276k free,    68728k buffers
Swap:        0k total,        0k used,        0k free,  3750664k cached

大多数流程如下:

24720 www-data  15   0  202m  26m 4412 S    9  0.3   0:02.97 apache2                                                                       
24530 www-data  15   0  212m  35m 4544 S    7  0.5   0:03.05 apache2                                                                       
24846 www-data  15   0  209m  33m 4420 S    7  0.4   0:01.03 apache2                                                                       
24083 www-data  15   0  211m  35m 4484 S    7  0.5   0:07.14 apache2                                                                       
24615 www-data  15   0  212m  35m 4404 S    7  0.5   0:02.89 apache2            

vmstat与上述同时的输出示例:

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 8  0      0 215084  68908 3774864    0    0   154   228    5    7 32 12 42  9
 6 21      0 198948  68936 3775740    0    0   676  2363 4022 1047 56 16  9 15
23  0      0 169460  68936 3776356    0    0   432  1372 3762  835 76 21  0  0
23  1      0 140412  68936 3776648    0    0   280     0 3157  827 70 25  0  0
20  1      0 115892  68936 3776792    0    0   188     8 2802  532 68 24  0  0
 6  1      0 133368  68936 3777780    0    0   752    71 3501  878 67 29  0  1
 0  1      0 146656  68944 3778064    0    0   308  2052 3312  850 38 17 19 24
 2  0      0 202104  68952 3778140    0    0    28    90 2617  700 44 13 33  5
 9  0      0 188960  68956 3778200    0    0     8     0 2226  475 59 17  6  2
 3  0      0 166364  68956 3778252    0    0     0    21 2288  386 65 19  1  0

最后,Apache 的输出server-status

Server uptime: 31 days 2 hours 18 minutes 31 seconds
Total accesses: 60102946 - Total Traffic: 974.5 GB
CPU Usage: u209.62 s75.19 cu0 cs0 - .0106% CPU load
22.4 requests/sec - 380.3 kB/second - 17.0 kB/request
107 requests currently being processed, 6 idle workers

C.KKKW..KWWKKWKW.KKKCKK..KKK.KKKK.KK._WK.K.K.KKKKK.K.R.KK..C.C.K
K.C.K..WK_K..KKW_CK.WK..W.KKKWKCKCKW.W_KKKKK.KKWKKKW._KKK.CKK...
KK_KWKKKWKCKCWKK.KKKCK..........................................
................................................................

根据我有限的经验,我得出以下结论/问题:

  • 我们可能允许了太多KeepAlive请求

  • 我确实看到 vmstat 中等待 IO 的时间有些长,虽然不是一直有,也不是很多(我想是吧?),所以我不确定这是否是一个大问题,我对 vmstat 不太熟悉

  • 此外,在 vmstat 中,我在一些迭代中看到许多进程正在等待服务,这就是我认为我们的 Web 服务器上的初始页面加载延迟的原因,可能是错误的

  • 我们提供静态内容(75% 或更高)和脚本内容的混合服务,并且脚本内容通常占用大量处理器资源,因此在两者之间找到适当的平衡非常重要;从长远来看,我们希望将静态内容移到其他地方以优化两台服务器,但我们的软件目前还没有为此做好准备

如果有人有任何想法,我很乐意提供更多信息,另一个需要注意的是,这是一个高可用性生产安装,因此我对一次又一次的调整持谨慎态度,这就是为什么我还没有KeepAlive自己玩过像价值这样的东西。

答案1

首先我承认我不太了解在云端运行东西 - 但根据我在其他地方的经验,我认为这个网络服务器配置反映的流量相当低。运行队列如此之大表明没有足够的 CPU 来处理它。运行队列中还有什么?

我们可能允许了太多的 KeepAlive 请求

不 - keeplive 仍然能提高性能,现代浏览器非常聪明,知道何时进行管道传输以及何时并行运行请求,尽管 5 秒的超时时间仍然相当长,而且你有一个很多服务器等待时间 - 除非您遇到严重的延迟问题,否则我建议将其降低到 2-3。这应该会缩短运行队列。

如果您尚未在 Web 服务器上安装 mod_deflate - 那么我建议您这样做 - 并将 ob_gzhandler() 添加到您的 PHP 脚本中。您可以将其作为自动添加项执行:

if(!ob_start("ob_gzhandler")) ob_start();

(是的,压缩会使用更多的 CPU - 但是您应该通过让服务器更快地退出运行队列/处理更少的 TCP 数据包来节省总体 CPU - 而且作为奖励,您的网站也会更快)。

我建议为 MaxRequestsPerChild 设置一个上限 - 比如说 500。这只会在出现内存泄漏时允许进程进行一些周转。您的 httpd 进程看起来非常庞大 - 确保您已删除所有不需要的 apache 模块,并确保您使用良好的缓存信息提供静态内容。

如果您仍然看到问题,那么问题可能出在 PHP 代码中(如果您切换到使用 fastCGI,这应该是显而易见的,而不会造成任何重大的性能损失)。

更新

如果静态内容在各个页面上差异不大,那么可能值得尝试一下:

if (count($_COOKIE)) {
    header('Connection: close');
}

PHP 脚本也是如此。

答案2

您应该考虑安装异步反向代理,因为 W 状态的进程数量也相当高。您的 Apache 进程似乎花费大量时间通过网络向慢速客户端发送内容,但网络因此被阻止。Nginx 或 lighttpd 作为 Apache 服务器的前端可以大大减少 W 状态的进程数量。是的,您应该限制 keepalive 请求的数量。也许值得尝试关闭 keepalive。

顺便说一句,107 个 Apache 进程对于 22 rps 来说太高了,我仅使用 5 个 Apache 进程就能提供 100-120 rps。下一步可能是分析您的应用程序。

答案3

您的 vmstat 中有两行显示您的 CPU 等待时间相当长,并且在这两行周围,您进行了相当多的写入 (io - bo) 和上下文切换。我会查看写入阻塞的原因以及如何消除这种等待。我认为最大的改进在于改进磁盘 IO。检查 syslog - 将其设置为异步写入。确保您的控制器的写入缓存正常工作(检查它 - 您的电池可能坏了)。

Keepalive 不会导致您的性能问题,如果您不在前面运行缓存,它可以节省您设置连接的时间。您可以稍微增加 MaxSpareServers,以便在关键时刻您不必等待所有分叉。

答案4

第一个建议:禁用 keepalive。我只在能够确定特定情况时才需要它,即启用 Keepalive 后性能会提高,但总体而言每秒请求数会减少。

第二个建议:设置 MaxRequestsPerChild。我在这里回应 symcbean,它将有助于在发生内存泄漏时进行进程翻转。500 是一个很好的起点。

第三个建议:增加 MaxClients。对此的一个大致计算是(物理内存 - 非 httpd 进程使用的内存)/每个 httpd 进程的大小。根据 httpd 的编译方式,此数字最大为 255。我将 250 用于我的公共服务器,以应对 google/yahoo/MS 抓取系统。

第四条建议:增加 MaxSpareServers:例如 4-5x MinSpareServers。

除非这些建议失败,否则我会研究使用反向代理或 memcache 为 DB 实现负载平衡。

相关内容