PHP-FPM

CGI是Common Gateway Interface(通用网管协议),用于让交互程序和Web服务器通信的协议。它负责处理URL的请求,启动一个进程,将客户端发送的数据作为输入,由Web服务器收集程序的输出并加上合适的头部,再发送回客户端。

FastCGI是基于CGI的增强版本的协议,不同于创建新的进程来服务请求,使用持续的进程和创建的子进程来处理一连串的进程,这些进程由FastCGI服务器管理,开销更小,效率更高。

PHP-FPM是PHP实现的FastCGI Process Manager(FastCGI进程管理器), 用于替换PHP FastCGI的大部分附加功能,适用于高负载网站。支持的功能如:

  • 平滑停止/启动的高级进程管理功能
  • 慢日志记录脚本
  • 动态/静态子进程产生
  • 基于php.ini的配置文件

PHP-FPM在5.4之后已经整合进入PHP源代码中,提供更好的PHP进程管理方式,可以有效控制内存和进程,平滑重载PHP配置。

最大进程数

如何控制子进程,为了高性能建议使用 pm static

pm = dynamic: 子进程的数量根据以下配置动态设置 pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers

pm = ondemand: 进程在请求时按需创建,而不是动态的,其中 pm.start_servers 进程数量在服务启动时创建

pm = static: 子进程的数量由 pm.max_children 决定

  • pm.max_children:php-fpm进程数量,如256
  • pm.start_servers:动态方式下的起始php-fpm进程数量
  • pm.min_spare_servers:动态方式下的最小php-fpm进程数
  • pm.max_spare_servers:动态方式下的最大php-fpm进程数量

最大活跃进程数

Active Processes: 设定为 256, 设置过高的话,很容易造成 web 服务器 CPU 占用过高等情况

管理方式

PHP-FPM管理的方式是一个master主进程,多个pool进程池,多个worker子进程。其中每个进程池监听一个socket套接字。具体的图示:

image

其中的worker子进程实际处理连接请求,master主进程负责管理子进程:

1
2
3
4
5
1. `master`进程,设置1s定时器,通过`socket`文件监听
2. 在`pm=dynamic`时,如果`idle worker`数量<`pm.min_spare_servers`,创建新的子进程
3. 在`pm=dynamic`时,如果`idle worker`数量>`pm.max_spare_servers`,杀死多余的空闲子进程
4. 在`pm=ondemand`时,如果`idle worker`空闲时间>`pm.process_idle_timeout`,杀死该空闲进程
5. 当连接到达时,检测如果`worker`数量>`pm.max_children`,打印`warning`日志,退出;如果无异常,使用`idle worker`服务,或者新建`worker`服务

保障基本安全

我们为了避免PHP-FPM主进程由于某些糟糕的PHP代码挂掉,需要设置重启的全局配置:

1
2
3
# 如果在1min内有10个子进程被中断失效,重启主进程
emergency_restart_threshold = 10
emergency_restart_interval = 1m

进程数限制

此时如果我们分配全部的内存给PHP-FPM使用,那么进程数可以限制在157000/27 = 5814,但是由于我的服务器同时服务了很多内容,所以我们可以向下调整到512个进程数:

1
2
3
4
5
6
process.max = 512
pm = dynamic
pm.max_children = 512
pm.start_servers = 16
pm.min_spare_servers = 8
pm.max_spare_serveres = 30

防止内存泄漏

由于糟糕的插件和库,内存泄漏时有发生,所以我们需要对每一个子进程服务的请求数量做限制,防止无限制的内存泄漏:

1
pm.max_requests = 1000

php-fpm 执行命令

如果上面的配置都按照你的实际需求和环境配置好了,不要忘记重启PHP-FPM服务。

1
2
3
4
sudo systemctl start php-fpm      # 启动php-fpm
sudo systemctl stop php-fpm       # 停止php-fpm
sudo systemctl reload php-fpm     # 重载php-fpm
sudo systemctl restart php-fpm    # 重启php-fpm

参考文章

PHP-FPM 调优:为了高性能使用 pm static

php-fpm进程数管理