浅谈 PHP-FPM

关于 FPM ,FastCGI ,CGI 之间的关系与区别。

一、概述

什么是 FPM ?

FPM 的全称是 FastCGI Process Manager ,即 PHP FastCGI 运行模式的一个进程管理器,从定义就可以看出它的核心功能是进程管理,那它用来管理什么进程呢,这个 FastCGI 又是什么东西,和 CGI 又有什么样的关系呢?

二、从 CGI 说起

先来看一段维基百科上的描述:

通用网关接口(Common Gateway Interface/CGI)是一种重要的互联网技术,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI描述了服务器和请求处理程序之间传输数据的一种标准。


CGI 是一种协议,用来保证 Web server 传递过来的数据是标准格式,以方便 CGI 程序的运行。而 Web server(例如 Nginx)承担的工作则是内容的分发,比如你要请求 /index.html,Web server 就会去文件系统中寻找这个文件,然后发送给浏览器,此时它分发的是静态资源。

PHP 是一个脚本解析器,在网络应用场景下并没有实现 HTTP 网络库,而是实现了对 CGI/FastCGI 这样的协议的解析,然后与 Web 服务器配合实现了 HTTP 的处理。

比如我们请求一个 /index.php ,根据配置,Web server 判断这是个动态资源,然后寻找 PHP 解析器进行处理。当收到一个匹配 URL 的请求时,相应的程序就会被调用,例如 PHP 解析器会解析 php.ini 文件然后初始化执行环境,并将客户端发送的数据(URL、查询的数据、HTTP header 等)作为输入,经过处理之后(比如定义的一些函数功能),程序的输出会被 Web 服务器收集,并加上合适的档头返回给客户端。

三、FastCGI 的诞生

现在我们知道 CGI 只是一种协议,而 FastCGI 则是一种优化了 CGI 的协议。优化的地方,就在刚刚提到的 PHP 解析器解析 php.ini 文件并初始化执行环境 这部分。标准的 CGI 程序对每个请求都会执行这些操作,如果用户还要再次请求动态资源,Web 服务器将重新 fork 一个新的进程,这显然是一种很低效的做法,尤其是在高负载下,操作系统创建和销毁进程的开销将十分巨大。

FastCGI 不是为每一个请求创建进程,而是通过 master-worker 这样的模型,使用持久化进程来处理请求。即在服务器启动时便创建 master 与 一定数量的 worker,在请求到来时 master 可以持续分配 worker 去处理请求。FastCGI 会维护一个进程池,根据资源与请求状况调整 worker 数量以节省资源,提高性能。

四、FPM 的实现

从 PHP54 开始,PHP 官方加入了 FPM 来管理 FastCGI 的进程。注意,在这之后 PHP-FPM 与 PHP-CGI 没有任何关系。PHP-FPM 是对 FastCGI 的具体实现,而 PHP-CGI 只是个 CGI 程序,并不会管理进程。

简单来说,FPM 的实现就是创建一个 master 进程,在 master 进程中创建并监听 socket,然后 fork 出多个子进程,这些子进程各自接受请求。子进程的处理非常简单,它在启动后阻塞在 accept 上,有请求到达后开始读取请求数据,读取完成后开始处理然后再返回,在这期间是不会接收其它请求的,也就是说 FPM 的子进程同时只能响应一个请求,只有把这个请求处理完成后才会 accept 下一个请求。

FPM 的 master 进程与 worker 进程之间不会直接进行通信,master 通过共享内存获取 worker 进程的信息,比如 worker 进程当前状态、已处理请求数等,当 master 进程要 kill 一个 worker 进程时则通过发送信号的方式通知 worker 进程。

FPM 可以同时监听多个端口,每个端口对应一个 worker pool,而每个 pool 下对应多个 worker 进程,类似 Nginx 中 Server 的概念。

我们在配合 Nginx 的使用的时候,常常会遇到 502 的错误,这是因为没有可用的进程了,就返回了错误。如果是 worker 进程处理请求超时,则返回 504 错误。

关于 FPM 的详细实现可以参考 PHP7 内核剖析 - fpm 这篇文章。

  1. 1. 一、概述
  2. 2. 二、从 CGI 说起
  3. 3. 三、FastCGI 的诞生
  4. 4. 四、FPM 的实现