FastCGI与PHP-FPM

要想弄清FastCGI和PHP-FPM,就需要先弄清一些基本的概念: CGIFastCGIPHP-FPMPHP-CGI

CGI

通用网关接口,描述的服务器和请求处理程序之间的数据传输的一种标准。

这可以简单的理解为CGI就是保证web server传过来的数据是标准的,能够方便的请求处理程序的编写。

在这一层面之上,web server只是请求内容的分发者。比如,如果请求index.html,那么web server会去文件系统中查找这个文件,然后发送到浏览器,那么这里分发的就是静态资源。如果这个时候请求的不是index.html而是index.php的话,根据web server(比如nginx)的配置文件,server判断出此次请求的不是静态文件,而是一个PHP的程序,需要去找PHP解析器来处理,那么server会简单处理这个请求后交给PHP解析器。Nginx会将请求的URLGET/POST数据HTTP Header等协议规定好的数据传递到处理请求的CGI程序中。

让我们在具体一点的分析。当server收到index.php这个请求后,server会启动对应的CGI程序,本文中指的就是PHP的解析器。接下来PHP解析器会解析配置文件php.ini,初始化运行环境,然后处理请求,最后按照CGI规定的数据格式返回处理结果,同时退出当前的CGI程序的进程。server将CGI程序的结果返回到浏览器中。

说了这么多,重点就是CGI是一个相互通信的协议,是一种双方约定好的标准。

FastCGI

在上面的CGI中,我们可以看到,当请求来临的时候CGI会初始化运行环境,然后处理请求,标准的CGI会对每一个请求都执行这些操作,所以每次的处理时间会很长,毕竟频繁的启动进程会消耗大量的资源。

FastCGI就是为了解决这种缺陷而出现的。FastCGICGI的增强版,为了减少web serverCGI程序之间的互动开销,从而使server能够同时处理更多的请求。

那么FastCGI是如何做到的呢?首先,FastCGI会先启动一个master进程,解析配置文件,初始化运行环境,然后在启动多个worker进程。当请求来临时,server将请求传递到mastermaster将请求传递给一个已经启动了的worker,然后就可以接收下一个请求;worker处理完请求便可以直接将处理的标准输出和错误信息返回到server。这样就避免了每次处理请求时都需要做的forkCGI进程的工作。当请求太多,worker不够用的时候,master可以根据配置文件预先启动多个worker等着;当worker空闲太多时,也会停掉一些。大多数的FastCGI实现都会维护一个进程池(swoole作为HttpServer时,就是类似这样的工作方式)。

到现在我们了解了CGIFastCGI

由于CGI处理每一个请求都需要fork新的进程,效率底下,就出现了CGI的增强版FastCGI,FastCGI维护一个自己的进程池来避免fork新进程的开销,从而大大的提高了性能。

PHP-CGI、PHP-FPM

PHP-CGI是PHP自带的FastCGI管理器,然而他却存在着比较严重的问题:

  1. PHP-CGI变更php.ini配置后需重启PHP-CGI才能让新的php-ini生效,不可以平滑重启.
  2. 直接杀死PHP-CGI进程,PHP就不能运行了。(PHP-FPM就没有这个问题,守护进程会平滑从新生成新的子进程。)

针对上面的两个问题,PHP-FPM便应运而生。PHP-FPM提供了更好的PHP进程管理方式,可以有效控制内存和进程、可以平滑重载PHP配置。由于PHP-FPM的优异表现,PHP官方在PHP5.3.3中集成PHP-FPM,使得PHP-FPM越来越受欢迎。