BLOG
PHP-FPM进程数量如何适配2核2G服务器
进程开得太多会耗尽内存,太少又会让请求排队,需要结合实际占用调整。
先确认这台2核2G服务器上跑的是什么类型的应用。纯静态页面、轻量CMS还是带队列和图片处理的框架,对PHP-FPM进程数的要求完全不同。2G内存不算宽裕,进程开多了内存耗尽,系统开始用swap,响应时间会急剧恶化;开少了请求排队,CPU闲置,用户看到的就是页面转圈。调整的目标不是某个固定数值,而是让进程数落在内存能承受、CPU又能跑满的区间里。
先看内存再谈进程数
每个PHP-FPM进程都会占用一定内存,这个数值取决于框架本身、已加载的扩展以及单个请求实际处理的数据量。同一个配置在不同项目上,单进程内存可能差出一倍。所以第一步不是改配置,而是先测量。
登录服务器后执行ps aux | grep php-fpm,观察输出里每个php-fpm进程的RSS列,也就是常驻内存集。把几个空闲进程和忙碌进程的内存占用分别记下来。空闲进程代表的是基础开销,忙碌进程代表的是请求处理时的峰值占用。取一个相对常见的中间值作为估算基准,比如某个进程稳定占用80MB,那2G内存减去系统、MySQL、Nginx等必要占用后,假设剩下1.2G可用,粗略估算就是1200除以80,大约能开15个进程。这个数字只是起点,不是最终答案。
同时用free -h查看当前内存使用情况,重点看available这一列,而不是total或used。available才是真正可以分配给新进程的内存。如果available长期低于200MB,说明当前配置已经偏紧。
配置项里只需要关注三个值
PHP-FPM的配置文件通常位于/etc/php-fpm.d/www.conf或/etc/php/8.x/fpm/pool.d/www.conf,具体路径随发行版和PHP版本不同。修改前先复制一份备份,例如cp www.conf www.conf.bak,改动后如果出现问题可以快速还原。
需要调整的参数有三个。pm.max_children是最大子进程数,决定了PHP-FPM最多能同时处理多少个请求,这是最核心的限制。pm.start_servers是启动时预创建的空闲进程数,pm.min_spare_servers和pm.max_spare_servers则控制空闲进程的上下限。当pm设置为dynamic时,PHP-FPM会根据请求量在这几个值之间自动调整。
对于2核2G的服务器,建议从保守值开始:max_children设为10到15之间,start_servers设为3到4,min_spare_servers设为2到3,max_spare_servers设为6到8。这些数字不是拍脑袋定的,而是根据前面测得的单进程内存乘以进程总数,确保总和不超过可用内存的70%到80%。如果单进程内存偏高,比如超过150MB,那max_children应该下调到8甚至更低。
修改完成后执行systemctl reload php-fpm或service php-fpm reload让配置生效。reload不会中断正在处理的请求,比restart更安全。
改完以后看三个地方
配置生效后不能只看网站能打开就算成功,需要观察一段时间的实际运行状态。
第一是进程数量是否稳定。执行ps aux | grep php-fpm | wc -l,注意这个数字包含了grep进程本身,实际PHP-FPM进程数要减一。在低峰期观察进程数是否回落到min_spare_servers附近,高峰期是否接近max_children但从未超过。如果进程数长期顶在max_children,说明上限设低了,请求在排队;如果长期只有两三个进程在跑,说明上限设高了,内存被白白占用。
第二是慢日志和错误日志。PHP-FPM的slowlog参数可以记录执行超过指定时间的请求,默认配置中通常已经开启,日志路径在配置文件里可以找到。查看慢日志中是否有大量请求超过10秒或30秒,如果存在,说明不是进程数不够,而是某个接口本身执行太慢,比如数据库查询没有索引或调用了外部API。这种情况下增加进程数只会让更多请求同时卡住,内存消耗更快,正确做法是单独优化慢请求。
第三是内存的长期趋势。用free -h每隔几分钟查看一次,连续观察半小时以上。如果内存占用持续上升且不回落,可能存在内存泄漏,表现为单个PHP-FPM进程的RSS随时间不断增长。此时重启PHP-FPM能暂时缓解,但根本原因通常在扩展或应用代码里,需要进一步排查。
容易踩的坑
最常见的错误是把max_children设得过大。有些人看到服务器还有几百MB空闲内存,就把进程数调到30甚至50,结果一旦流量波动,所有进程同时处理请求,内存瞬间耗尽,系统开始使用swap,整个服务器响应变慢,MySQL也可能因为内存不足而崩溃。这种故障比请求排队更严重,因为恢复需要手动干预。
另一个容易忽略的问题是每个请求的内存峰值。空闲进程占用可能只有50MB,但处理图片缩放或导出报表时可能涨到200MB以上。如果只按空闲内存估算进程数,高峰期就会出问题。稳妥的做法是按忙碌进程的内存峰值来算,或者把max_children设得比估算值再低20%左右,留出安全余量。
还有一个问题是把pm.max_requests设得过大或过小。这个参数控制每个子进程处理多少个请求后自动重启,主要作用是防止长期运行的进程积累内存碎片。默认值500到1000通常够用,不需要频繁调整。设得太小会导致进程频繁重启,增加CPU开销;设得太大则失去防止内存泄漏的意义。
什么时候需要调整
如果网站流量持续增长,日志里频繁出现server reached pm.max_children的警告,说明进程数确实不够。此时先看单进程内存是否有优化空间,比如关闭不用的PHP扩展、升级到更新版本,然后再考虑增加max_children。如果内存已经吃紧,增加进程数只是饮鸩止渴,真正该做的是升级服务器配置或优化应用性能。
反过来,如果服务器长期处于低负载,进程数大多数时间都停在最小值附近,可以适当调低max_children和max_spare_servers,把内存留给系统缓存和数据库。
每次调整后保留一份修改记录,写明改了什么值、当时的观察数据、调整原因和验证结果。下次再遇到类似问题时,这份记录能帮你快速定位是配置漂移还是流量变化导致的异常。
评论
登录后可发表评论。