PHP-FPM 运行原理分析
概述
PHP-FPM 是一种 Master / Worker 多进程运行模式,进程的数量可以通过 php-fpm.conf 进行具体的配置。
Master 进程主要负责 CGI、PHP 环境的初始化、事件循环、监听子进程状态等。
Woker 主要负责处理 PHP 的请求。
PHP-FPM 运行模式
PHP-FPM 支持三种运行模式,分别是 静态模式 static
、按需模式 ondemand
、动态模式 dynamic
。
- static 静态模式
直接开启指定数据量的 PHP-FPM 进程,不再增加或者减少。
启动固定数量的进程,占用内存高。
但是在用户请求波动大的时候,对 Linux 系统的处理耗费的系统资源底。
- ondemand 按需模式
PHP-FPM 的 Master 不会 Fork 任何的子进程,只有收到用户请求时才会 fork worker 进程,这种模式很少使用。
因为它基本无法适应由一定量级的线上业务,由于 PHP-FPM 是短连接,所以每次请求都会先建立连接。
在大流量的系统上 Master 进程会变得非常繁忙,占用系统 CPU 资源,不适合大流量环境的部署。
- dynamic 动态模式
启动时分配固定的进程,随着请求数的变化,在设定的浮动范围调整 worker 进程。
开启一定数量的 PHP-FPM 进程,当请求量变大的时候,动态增加 PHP-FPM 进程数量达到上限,当空闲的时候自动释放空闲进程数到下一个下限。
会根据 max、min、idle children 配置,动态的调整进程数量。
在用户请求波动较大,或者瞬间请求量变大的时候,会进行大量进程的创建和销毁操作,而引起 Linux 系统的负载增高。
运行原理
PHP-FPM 使用 master/worker 架构设计。
Master 进程
CGI 初始化阶段
分别调用 fcgi_init() 函数 和 sapi_start_up() 函数,注册进程信号以及初始化 sapi_globals 全局变量。
PHP 环境初始化阶段
由 cgi_sapi_module.start_up 触发,实际上调用 php_cgi_start_up 函数,而 php_cgi_start_up 内部又调用 php_module_start_up 执行。
php_module_start_up 主要功能包括:
1、加载和解析 PHP 配置文件。
2、加载 PHP 模块并记入函数符号表 (function_table)。
3、加载 Zend 扩展。
4、设置禁用函数和类库配置。
5、注册回收内存方法。
PHP-FPM 初始化阶段
执行 fpm_init() 函数,负责解析 php-fpm.conf 文件配置,获取进程相关参数,例如:允许进程打开的最大文件数。
初始化进程池及事件模型等操作。
PHP-FPM 运行阶段
执行 fpm_run() 函数,运行后主进程发送阻塞。
此阶段包括 fork 子进程和事件循环两个部分:
1、fork 子进程交由 fpm_children_create_initial 函数处理。
2、事件循环通过 fpm_event_loop 函数处理,其内部是一个死循环,负责事件的收集工作。
Worker 进程
woker 进程分为 接收客户端请求、处理请求、请求结束三个阶段。
接收客户端请求
执行 fcgi_accept_request 函数,其内部通过调用 accept 函数获取客户端请求。
处理请求阶段
首先,分别调用 fpm_request_info、php_request_start_up 获取请求内容及注册全局变量($_GET、$_POST、$_SERVER、$_ENV、$FILES)。
然后,根据请求信息调用 php_fopen_primary_script 访问脚本文件。
最后,交给 php_execute_script 执行。执行 php_execute_script 内部调用 zend_execute_scripts 方法将脚本交给 zend 引擎处理。
请求结束阶段
执行 php_request_shutdown 函数,此时回调 register_shutdown_function 注册的函数及 __destruct() 方法,发送响应内容、释放内存等操作。