⚙️
Hosting

现代网络服务器每分钟处理数千个 HTTP 请求,PHP 引擎如何处理这些请求直接影响网站速度、内存使用和整体稳定性。在本指南中,我们将深入探讨 PHP-FPM(FastCGI Process Manager) — 它是什么、与旧方法相比如何工作、为什么已成为生产环境的标准,以及如何调优其配置以在您的 VPS 或专用服务器上实现最佳性能。

简而言之: PHP-FPM 是一个进程管理器,它维护一个随时可用的 PHP 工作进程池,然后将传入的请求路由到空闲的工作进程 — 而不是像旧的 CGI 方式那样为每个请求生成一个新的 PHP 进程,也不像 mod_php 那样直接将 PHP 嵌入 Apache。这种设计使用更少的内存、减少延迟并增加吞吐量。要优化 pm.max_children 和其他调优参数以适应服务器的 RAM,请检查 DirectAdmin 的 PHP 选择器(如果可用),或联系 AsiaGB 客服获取建议。

什么是 PHP-FPM?

PHP-FPM 代表 FastCGI Process Manager,是在网络服务器上处理 PHP 的现代标准。核心概念很优雅:与其等待 HTTP 请求到达然后从零开始生成全新的 PHP 进程(这需要时间),不如 PHP-FPM 预先创建并持续维护一个"进程池"的 PHP 工作进程。当请求到达时,主进程立即将其分配给一个可用的工作进程。如果所有工作进程都很忙,请求将在队列中等待。可以想象成有一个员工团队随时坐在办公桌上,而不是为每个客户从街上雇一个临时工 — 速度快得多,效率高得多。

PHP-FPM vs. Mod_PHP vs. PHP-CGI

PHP-CGI(旧版): 每当网络服务器收到一个 .php 请求时,它都会生成一个全新的 PHP 进程,处理文件,输出结果,然后杀死该进程。这会产生显著的 CPU 开销(进程启动),在高流量下服务器会生成数千个进程,导致内存耗尽和系统减速或崩溃。

Mod_PHP(内置): 直接将 PHP 引擎嵌入 Apache 的工作进程。没有生成开销,但每个 Apache 工作进程都携带完整的 PHP 运行时 — 所以有 300 个 Apache 工作进程的服务器必须加载整个 PHP 库 300 次。一个 4GB 的服务器运行 Mod_PHP 通常会进行交换并变得无法使用。

PHP-FPM(现代): 一个独立的进程管理器创建一个小的、托管的 PHP 工作进程池(通常 5–50 个进程),这些进程处于空闲状态,直到请求到达。当网络服务器(Nginx 或 Apache)收到 PHP 请求时,它通过 Unix 套接字或 TCP 连接将其转发到 FPM 主进程。主进程选择一个空闲的工作进程,将请求发送给它;如果没有空闲的工作进程,请求将排队。这使用的内存只是一小部分(无需全天运行 300 个 PHP 进程),延迟接近零,并且在负载下可以平稳扩展。

指标 PHP-CGI Mod_PHP PHP-FPM
进程创建 每个请求创建新进程 嵌入在 Apache 中 预先创建的进程池
每个请求的内存 高(启动成本) 非常高(300 个进程) 低(5–50 个进程)
延迟 高(启动延迟) 非常低
可扩展性 中等 优秀
支持的网络服务器 所有 仅 Apache Nginx、Apache 等

进程池配置参数

PHP-FPM 的强大之处在于其可配置性。进程池设置位于配置文件中,如 /etc/php/8.1/fpm/pool.d/www.conf(Linux),或通过 DirectAdmin 之类的控制面板进行设置。AsiaGB 客户通常可以使用 DirectAdmin PHP 选择器来选择 PHP 版本和调整进程池参数,无需 SSH 访问权限。

pm(进程管理器模式): 控制进程池如何扩展。

pm.max_children: 一次允许的最大工作进程数。如果所有 pm.max_children 个进程都很忙,新请求将排队。设置过高,服务器会内存不足;设置过低,高流量会导致 502 Bad Gateway 错误或超时。

pm.start_servers、pm.min_spare_servers、pm.max_spare_servers: 仅在 pm = dynamic 模式下使用。您告诉 FPM:"在启动时创建 X 个进程。保持至少 Y 个空闲进程,但不超过 Z 个空闲进程。"例如,pm.start_servers = 10, pm.min_spare_servers = 5, pm.max_spare_servers = 20 表示 FPM 启动时有 10 个工作进程;如果空闲进程数低于 5,它会生成更多;如果空闲进程数超过 20,它会杀死多余的进程。

pm.max_requests: 回收工作进程之前处理的请求数。防止内存泄漏:即使脚本有微妙的内存泄漏错误,每个请求额外使用 1MB,在 1000 个请求后回收会限制泄漏。例如:pm.max_requests = 1000 表示每个工作进程在处理 1000 个请求后死亡并重新生成。

request_terminate_timeout: PHP 脚本在被 FPM 强制杀死之前可以运行的最长秒数。默认通常为 30 秒;对于后台任务增加到 300。注意,您的网络服务器(Nginx)可能也有自己的超时 — 它们会堆叠。

如何检查您当前的 PHP 处理器

不确定您的托管使用 PHP-FPM、Mod_PHP 还是 CGI?通过几种方式检查:

通过 phpinfo(): 创建一个仅包含 <?php phpinfo(); ?> 的文件,上传它,并查看"Server API"。您会看到"FPM/FastCGI"(PHP-FPM)、"Apache 2.0 Handler"(Mod_PHP)或"CGI"(CGI 模式)。

通过 SSH(如果您有 shell 访问权限):

ps aux | grep php

如果您看到多行像 php-fpm: pool www 的输出,您的托管运行 PHP-FPM。如果没有出现 php 进程,很可能是 Mod_PHP(在 Apache 内运行)。

502 Bad Gateway 问题

注意: 502 Bad Gateway 的常见原因是 pm.max_children 设置过小。当流量激增且所有 PHP 工作进程都很忙时,新请求无处可去;网络服务器无法连接到可用的 FPM 工作进程并返回 502。另一个原因是 request_terminate_timeout 对于长时间运行的脚本来说太短;脚本在执行中途被杀死,网络服务器看到破坏的连接。解决方案:增加 pm.max_children(同时监控以确保有足够的 RAM),或提高 request_terminate_timeout,如果脚本确实需要更多时间。

通过状态页面监控 PHP-FPM

小贴士: PHP-FPM 包含一个隐藏的状态页面,显示实时指标:空闲进程数、接受的连接、慢请求数等。要启用它,编辑 /etc/php/8.1/fpm/pool.d/www.conf(或使用 DirectAdmin PHP 选择器,如果它公开该设置)并设置 pm.status_path = /fpm-status,然后重新启动 FPM。然后可以从服务器的 shell(或通过 SSH 隧道)查询 http://localhost/fpm-status 以查看诸如"空闲进程:3 个(共 10 个)"、"慢请求:0"等统计信息。如果"空闲进程"始终为零,您的进程池太小;如果"慢请求"很高,请检查 request_terminate_timeout

性能调优指南

主要目标是正确调整 pm.max_children 的大小,以便所有请求都能快速获得工作进程,而不会耗尽 RAM。

粗略公式:

pm.max_children = (总可用 RAM - 操作系统开销) / 平均 PHP 进程内存

示例: 一个 4GB 的 VPS,操作系统和服务使用约 500MB,您测量空闲 PHP 进程使用约 30–50MB(平均 40MB):

pm.max_children = (4096 MB - 500 MB) / 40 MB 每个进程 ≈ 90 个进程

但是,不要盲目最大化它。当每个请求需要 3–5 秒时设置 90 个进程意味着仅保持所有工作进程忙碌就需要约 450 个 CPU 毫秒/请求 — 这是您所有 CPU 核心的最大利用率。还要考虑高进程数会增加上下文切换开销。从保守的设置开始,监控,如果需要则增长。

调优步骤:

  1. 监控 PHP 进程当前使用的内存(检查 top 或 FPM 状态页面)。
  2. 使用上面的公式计算 pm.max_children
  3. 编辑配置文件并设置新值,然后重新启动 PHP-FPM。
  4. 立即检查 FPM 状态和日志中的错误。
  5. 运行负载测试(例如,ab -n 10000 -c 100 http://yoursite.com/)以查看是否出现 502 错误或延迟激增。
  6. 如果出现 502 错误,进一步增加 pm.max_children
  7. 如果服务器内存不足(检查 dmesg 或系统日志中的 OOM killer),减少 pm.max_children
  8. 重新测试并迭代直到稳定。

对于共享托管(动态模式): 如果您受到限制并使用 pm = dynamic,减少 pm.max_spare_servers(例如,10 而不是 35)以减少空闲内存使用,同时保持 pm.min_spare_servers 合理(例如,5)以实现快速响应时间。

一台服务器上多个网站的多进程池配置

当一台服务器同时托管多个网站时,所有网站共用一个 FPM 进程池可能会出问题:高流量网站会抢占低流量网站的工作进程。解决方法是为每个网站创建单独的进程池,在 pool.d/ 目录中添加新的配置文件,例如 site-a.confsite-b.conf。每个文件定义自己的进程池名称(如 [site-a]),监听独立的套接字,例如 /run/php/site-a.sock,并根据该网站的预期流量设置 pm.max_children。这样,一个网站上失控的脚本(例如无限循环)就不会耗尽其他网站在同一服务器上的 PHP 工作进程,因为每个进程池都有自己独立的工作进程和内存上限。

对于管理多个客户账户的管理员来说,按域名分离进程池还能提升安全性:每个进程池可以以不同的 usergroup 运行(类似 DirectAdmin 的 PHP Selector 为每个账户隔离权限的方式),防止一个网站的文件被另一个网站的 PHP 进程读取或写入,即使它们共享同一台物理服务器。这是共享主机提供商用来隔离客户账户的标准做法。

Nginx 与 PHP-FPM:Unix 套接字与 TCP 连接对比

当 Nginx 将请求转发给 PHP-FPM 时,有两种连接方式:通过 Unix 套接字(磁盘上的文件,如 /run/php/php8.1-fpm.sock)或通过 TCP(如 127.0.0.1:9000)。Unix 套接字通常稍快一些,因为它绕过了操作系统的网络堆栈——当 Nginx 和 PHP-FPM 运行在同一台机器上时是理想选择。当 PHP-FPM 运行在与 Nginx 不同的机器上时(例如将 Web 服务器和应用服务器分离以独立扩展的架构),则需要使用 TCP。在 Nginx 的配置中,套接字方式会看到类似 fastcgi_pass unix:/run/php/php8.1-fpm.sock; 的行,TCP 方式则是 fastcgi_pass 127.0.0.1:9000;。这个值必须与 FPM 进程池配置中设置的 listen 指令匹配,否则会出现"No such file or directory"或"Connection refused"等错误。

总结

PHP-FPM 是现代、高性能网络托管的基石。通过维护托管的 PHP 工作进程池并智能地路由请求,它消除了进程创建的开销,并允许服务器处理远比旧方法(如 PHP-CGI)甚至 Mod_PHP 更多的并发流量。调优 pm.max_childrenpm 模式、pm.max_requestsrequest_terminate_timeout 以匹配您的实际工作负载可防止 502 错误、减少延迟并充分利用您的硬件。如果您使用 AsiaGB 的 DirectAdmin 托管,请检查 PHP 选择器以查看这些设置,或联系我们的支持团队以获取个性化的调优建议。

常见问题 (FAQ)

PHP-FPM 真的会让网站更快吗?

是的。PHP-FPM 保持工作进程预先创建并随时可用,消除了每个请求的启动开销。与为每个请求生成新进程的 PHP-CGI 相比,FPM 大幅减少延迟。对于高流量网站,感知速度的差异是显著的。

我应该将 pm.max_children 设置为多少?

使用公式(可用 RAM - 操作系统/服务开销)/平均 PHP 进程内存。对于 4GB VPS(每个进程 40MB),目标是约 90。确切的数字取决于测试:运行负载测试并监控,直到达到没有 502 错误且内存稳定的最优点。

为什么我的网站返回 502 Bad Gateway?

通常是因为 pm.max_children 太低 — 在流量激增时,所有 PHP 工作进程都很忙,新请求无法连接到空闲的工作进程。增加 pm.max_children,或如果脚本确实运行很长时间,提高 request_terminate_timeout。

我需要 SSH 来重新启动 PHP-FPM 吗?

不一定。AsiaGB 客户通常可以使用 DirectAdmin 的 PHP 选择器直接调整进程池设置;更改会快速生效。如果您的面板不公开该设置,请联系 AsiaGB 客服为您调整。

立即开始使用 AsiaGB Hosting

AsiaGB Hosting 采用 SSD 存储,通过简单易用的 DirectAdmin 控制面板管理,支持多个 PHP 版本,正常运行时间达 99%,价格实惠,并有泰语技术团队提供支持。

查看 Hosting 套餐

查看泰国虚拟主机全部套餐 →