在许多繁忙的企业网站日志中,会出现两条警告:Apache 的 “server reached MaxRequestWorkers setting” 和 PHP-FPM 的 “server reached pm.max_children setting”。两者含义相同:请求正在等待可用的工作进程。人的本能是调高这个数字然后了事,但在内存有限的服务器上,这样做换来的是页面变慢,以及服务器在最糟糕的时刻开始交换内存或耗尽内存。良好的 Apache 性能,来自按您实际拥有的 RAM 来确定 MaxRequestWorkers 和 PHP-FPM 的大小。本指南针对常见的现代配置逐步演示这一计算:Apache 2.4 采用 event MPM,前置于 PHP-FPM。
首先,确认您运行的是哪种 MPM 和 PHP 处理方式
只有了解架构,这些数字才有意义。apachectl -V 会在 “Server MPM” 一行显示当前的 MPM,而在 Debian 和 Ubuntu 上,a2query -M 只打印它的名称。在基于 Red Hat 的系统上,该服务叫 httpd,但 httpd 性能遵循同样的规则。然后检查 PHP 是如何运行的:通过 PHP-FPM(通常经由 proxy_fcgi),还是作为 Apache 内部的 mod_php。两者差别很大:
- prefork 搭配 mod_php:每个 Apache 进程都带着一个完整的 PHP 解释器,即使它只是发送一张图片。每个连接的内存很高,MaxRequestWorkers 实际上就是您的 PHP 上限。
- Apache event MPM 搭配 PHP-FPM:Apache 线程很轻,负责处理连接、静态文件和 keep-alive,而 PHP 在单独的进程池中运行。Apache 可以容纳多得多的连接,而 PHP-FPM 的 pm.max_children 成为保护内存的那项设置。
如果服务器仍在使用 prefork 搭配 mod_php,那么改用 event 搭配 PHP-FPM 通常是效果最明显的单项改动。不过它需要测试,因为 .htaccess 文件中的 php_value 行只对 mod_php 有效,必须迁移到 PHP-FPM 进程池或 .user.ini 文件中。
测量 Apache 内存占用和 PHP 进程大小
确定大小要从测量开始,而且要在正常的繁忙时段进行,而不是在清闲的周日早晨。请查看:
- 总 RAM 以及服务器上还有什么。数据库、Redis 之类的缓存、邮件服务和操作系统,在 Web 工作进程拿到内存之前,都需要各自的一份。
- PHP-FPM 进程的平均大小。用 ps 取 rss 列并过滤出 php-fpm 进程,可以得到一个可用的数字。请使用负载下的典型大小,而不是最小的空闲进程。
- 每个子进程的 Apache 内存占用。在 event MPM 下这通常不大,因为每个子进程内的线程共享内存。
Apache mod_status 配合 server-status 页面(限制为只有您自己的 IP 地址可访问)会显示记分板:有多少工作进程正忙于读取、写入或保持 keep-alive 连接。如果大多数都处于 keep-alive 状态,说明 KeepAliveTimeout 正在为空闲的浏览器占着位置。
确定 PHP-FPM pm.max_children
对于 PHP-FPM,可用的公式很简单:可分给 PHP 的内存,除以 PHP 进程的平均大小。例如,在一台 8 GB RAM 的服务器上,数据库、缓存和系统大约需要 4 GB,大约还剩 4 GB 给 PHP。按每个进程约 100 MB 计算,这允许大约 40 个子进程,明智的做法是从比这略低的数值开始,并观察。
还有两项设置很重要。一是进程管理器模式:dynamic 保持一定范围的进程待命,ondemand 只在需要时才启动进程,适合一台服务器上的许多小网站,static 则保持固定数量,适合一个繁忙的应用。二是 pm.max_requests,它在处理一定数量的请求后回收每个进程,这样插件中缓慢的内存泄漏就不会累积。请注意,PHP 自带的默认进程池文件把 pm.max_children 仅设为 5,所以使用默认设置的繁忙网站会很早就触及上限。
为 event MPM 确定 MaxRequestWorkers
在 event MPM 下,MaxRequestWorkers 是可同时处理请求的线程总数,而且必须不超过 ServerLimit 乘以 ThreadsPerChild。Apache 编译时的默认值是 16 个进程、每个 25 个线程,共 400 个,而发行版的配置文件常常设置得更低。由于 PHP-FPM 已经限制了 PHP 的工作量,event 服务器上的 MaxRequestWorkers 可以安全地高于 pm.max_children。额外的线程几乎不占内存,并让 Apache 能在 PHP 忙碌时继续提供图片、样式表和 keep-alive 连接。如果您把 MaxRequestWorkers 提高到超过 ServerLimit 乘以 ThreadsPerChild,也要同时调高 ServerLimit 并完整重启 Apache,因为平滑重载不会改变 ServerLimit。
在 prefork MPM 下,计算更严格:MaxRequestWorkers 乘以 Apache 进程的平均大小,必须容纳在留给 Apache 的内存之内,因为每个工作进程都是一个完整的进程。
KeepAlive、超时和测试结果
- KeepAliveTimeout。默认的 5 秒是合理的;过长的值会为已经完成的浏览器占着位置。event MPM 能高效处理空闲的 keep-alive 连接,这是偏爱它的另一个原因。
- Timeout。过长的请求超时会让少数缓慢或恶意的客户端占住工作进程。请让它与最慢的合法请求相匹配,例如大文件上传或报表。
- 一次只改一处。尽可能用平滑重载应用每项更改,在繁忙时段观察内存、记分板和响应时间,并保留之前的配置,以便回退。
同样的先测量后调整的方法适用于任何 Apache 优化项目,我们的 Apache 性能调优就是这样开始的。如果工作进程闲着,页面却依然很慢,瓶颈就在别处,通常是数据库查询或应用本身,这时就需要 MySQL 和 MariaDB 调优了。
常见问题:MaxRequestWorkers
警告出现时,我是不是直接调高 MaxRequestWorkers 就行?
只有在检查过内存之后才可以。如果服务器还有余量,适度提高没有问题。如果已经接近开始交换,更高的上限只会让情况更糟;答案是通过缓存减少请求、加快请求,或者增加内存。
WordPress 网站每个 PHP 进程需要多少 RAM?
这取决于插件和主题,所以测量您自己的进程胜过任何经验法则。繁忙的商店和页面构建器每个请求所需的内存往往明显高于简单的宣传型网站。
event MPM 与 .htaccess 文件搭配安全吗?
安全。MPM 不会改变 .htaccess 中重写和访问规则的工作方式。改变的是 PHP 的运行方式,所以要检查的是这些文件中的 PHP 设置是否需要迁移到 PHP-FPM 进程池。
在洛杉矶(Los Angeles)或长滩(Long Beach)的服务器上看到 MaxRequestWorkers 或 pm.max_children 警告?我们的 Apache Web 服务器优化服务从测量开始,然后把 MPM、PHP-FPM、缓存和安全加固一起调好。请联系我们,附上错误日志中的警告以及服务器的 RAM 容量。
Apache 服务器要花多少钱?
软件本身不花钱:Apache HTTP Server 是免费的开源软件,随 PHP 一起提供的 PHP-FPM 也是如此。实际上,真正重要的 Apache 服务器费用是硬件和围绕它的时间。工作进程数超过可用 RAM,会把服务器推入交换,而常见的捷径是买一台更大的机器。测量 PHP 进程的大小,让 pm.max_children 和 MaxRequestWorkers 与之匹配,再加上缓存,可以让现有的服务器在需要更多内存之前处理更多流量。




