WebServer 和 CGI 以及 PHPFPM 之间的关系

WebServer

最早的 Web服务器简单地响应浏览器发来的 HTTP 请求,并将存储在服务器上的 HTML 文件返回给浏览器,也就是静态HTML。

但事物总是不断发展的,网站也逐渐变得复杂,所以出现动态技术。但是 Web服务器并不能直接运行 php,asp 这样的文件,当浏览器请求 index.php?a=1&b=2 时,Web服务器就不知道该如何处理了,它不能理解 “php”、“?”、“&”、“a”、“b” 各是什么意思,这时它就需要调用相应的脚本解释程序(如PHP-CGI)来处理这样的请求。

CGI

Web服务器不知道如何处理动态页面请求,需要移交其他程序来处理,这时需要与该程序做个约定,我给你什么,然后你给我什么,就是我把请求参数(如 a=1,b=2)发送给你,然后我接收你的处理结果给客户端。那这个约定就是 Common Gateway Interface,简称 CGI。这个协议可以用 VB,C,PHP,Python 等语言来实现。

CGI 只是接口协议,根本不是什么语言。

WebServer 与 CGI 程序的交互

Web服务器将根据 CGI程序的类型决定数据向 CGI程序的传送方式,通常是通过标准输入/输出流和环境变量来传递。

CGI程序通过标准输入(STDIN)和标准输出(STDOUT)来进行输入输出。此外 CGI程序还通过环境变量来得到输入。

操作系统提供了许多环境变量,它们定义了程序的执行环境,应用程序可以存取它们。

Web服务器和 CGI接口又另外设置了一些环境变量,用来向 CGI程序传递一些重要的参数。

下面是一些常用的 CGI 环境变量:

变量名 描述
CONTENT_TYPE 这个环境变量的值指示所传递来的信息的MIME类型
CONTENT_LENGTH 如果服务器与 CGI 程序信息的传递方式是 POST,这个环境变量即是从标准输入 STDIN中可以读到的有效数据的字节数。这个环境变量在读取所输入的数据时必须使用
HTTP_COOKIE 客户机内的 COOKIE 内容
HTTP_USER_AGENT 提供包含了版本数或其他专有数据的客户浏览器信息
PATH_INFO 这个环境变量的值表示紧接在 CGI 程序名之后的其他路径信息。它常常作为 CGI 程序的参数出现
QUERY_STRING 如果服务器与 CGI 程序信息的传递方式是 GET,这个环境变量的值即使所传递的信息。这个信息经跟在CGI程序名的后面,两者中间用一个问号分隔
REMOTE_ADDR 这个环境变量的值是发送请求的客户机的 IP 地址,它是 WEB客户机需要提供给 WEB服务器的唯一标识,可以在 CGI 程序中用它来区分不同的 Web客户机
REMOTE_HOST 这个环境变量的值包含发送 CGI 请求的客户机的主机名。如果不支持你想查询,则无需定义此环境变量
REQUEST_METHOD 提供脚本被调用的方法。对于使用 HTTP/1.0 协议的脚本,仅 GET 和 POST 有意义
SCRIPT_FILENAME CGI 脚本的完整路径
SCRIPT_NAME CGI 脚本的的名称
SERVER_NAME 这是你的 WEB 服务器的主机名、别名或 IP 地址
SERVER_SOFTWARE 这个环境变量的值包含了调用 CGI 程序的 HTTP 服务器的名称和版本号。例如 Apache/2.2.14(Unix)

PHP-CGI

当 WEB服务器收到 index.php 这样的请求后,会启动对应的 CGI 程序,这里就是 PHP 的 CGI 程序,也就是 PHP-CGI。

接下来 PHP-CGI 会解析 php.ini 文件,初始化执行环境,然后处理请求,再以 CGI 规定的格式返回处理后的结果,退出进程。接着 Web服务器再将结果返回给浏览器。

FastCGI

CGI 是个协议,跟进程什么的没关系。那 FastCGI 又是什么呢?

FastCGI 是用来提高 CGI程序性能的。PHP-GGI 会对每个请求都执行解析 php.ini 文件,初始化执行环境这些步骤,处理每个请求的时间会比较长,随之便出现了 FastCGI。

Web服务器启动时会载入一个 FastCGI进程管理器(IIS ISAPI 或 Apache Module),解析配置文件,初始化执行环境,然后再启动多个 CGI解释器进程(PHP-CGI)等待 Web服务器的连接。

当请求到来时,FastCGI进程管理器会选择并连接到一个 PHP-CGI进程,Web服务器将 CGI环境变量和标准输入发送到该 PHP-CGI进程。

PHP-CGI进程完成处理后将标准输出和错误信息从同一连接返回给 Web服务器。当 PHP-CGI进程关闭连接时,请求便处理完成。PHP-CGI进程接着等待并处理来自 FastCGI进程管理器(运行在Web Server中)的下一个连接。

这样就避免了重复的劳动,效率自然得以提升。而且当 PHP-CGI进程不够用时,FastCGI进程管理器可以根据配置预先启动几个 PHP-CGI进程等着;而当空闲 PHP-CGI进程太多时,也会停掉一些,这样即提高了性能,也节约了资源。这就是 FastCGI 对进程的管理。

PHP-FPM

PHP-cgi 只是个 CGI 程序,他自己本身只能解析请求,返回结果,不会进程管理,所以就出现了一些能够调度 PHP-cgi 进程的程序,比如说由lighthttpd 分离出来的 spawn-fcgi。PHP-FPM 同样是调度 PHP-cgi 进程的程序,是 FastCGI 的一种实现,负责管理一个进程池。长时间的发展后,现在也逐渐得到了大家的认可,也越来越流行。

参考 & 扩展阅读