深入理解CGI与FastCGI:公共网关接口与常驻型CGI的对比与应用
其实你理解了下面的几个概念,那么本文所要解释的问题你也就理解了。CGI 是其中之一。它有着特定的含义和作用。另外还有其他相关概念。这些概念对于理解本文的问题都很重要。

CGI 全称为“公共网关接口”。它是一种工具,能够让 HTTP 服务器与你或其他机器上的程序进行“交谈”。并且这种程序必须运行在网络服务器上。
CGI 本身能够被视为一种协议标准。它能够用任何一种语言来编写具体的、符合该接口标准的协议。只要这种语言具备标准输入、输出和环境变量,就可以存在这样的协议。例如 php、perl、tcl 等。
FastCGI 就像一个长期存活的 CGI。它能够一直处于执行状态。只要被激活后,就不会每次都需要花费时间去进行 fork 操作(而这正是 CGI 最为人所诟病的 fork-and-execute 模式)。它支持分布式运算。FastCGI 程序能够在网站服务器之外的主机上进行执行。同时,它还可以接受来自其他网站服务器的请求。
FastCGI 是一种开放扩展。它与语言无关。它具有可伸缩的架构。它是 CGI 的扩展。其主要行为是把 CGI 解释器进程保持在内存中。通过这种方式能获得较高的性能。大家都知道,CGI 解释器反复加载是导致 CGI 性能低下的主要因素。如果 CGI 解释器能一直留在内存中,并且接受 FastCGI 进程管理器的调度,那么就能够提供良好的性能、具备良好的伸缩性以及具备 Fail-Over 特性等。
FastCGI 可以被称作一种协议标准。例如,后面要提到的 php-fpm 是一个支持解析 php 的 fastCGI 进程管理器/引擎。
FastCGI特点
FastCGI具有语言无关性.
FastCGI 在进程中的应用程序可独立于核心 web 服务器运行,它能提供比 API 更安全的环境。API 会将应用程序的代码与核心 web 服务器链接起来,这就导致一个错误的 API 应用程序有可能会损坏其他应用程序或核心服务器。恶意的 API 应用程序代码甚至有能力窃取另一个应用程序或核心服务器的密钥。
FastCGI 技术目前所支持的语言包含:C/C++,Java,Perl,Tcl,Python,SmallTalk,Ruby 等。并且在 Apache、ISS、Lighttpd 等这些流行的服务器上,相关模块是可以使用的。
FastCGI 不依赖于任何 Web 服务器的内部架构。所以即便服务器技术发生了变化,FastCGI 依然能够保持稳定不变。
FastCGI的工作原理
Web Server 启动时会载入 FastCGI 进程管理器,这个管理器可以是 IIS ISAPI 或者 Apache Module。
FastCGI 进程管理器进行自身的初始化。它启动了多个 CGI 解释器进程,这些进程可以被看到是多个 php-cgi。并且它在等待来自 Web Server 的连接。
客户端请求抵达 Web Server 后,FastCGI 进程管理器会进行选择并连接到一个 CGI 解释器。接着,Web server 把 CGI 环境变量以及标准输入传送给 FastCGI 子进程 php-cgi 。
FastCGI 子进程处理完毕后,会把标准输出和错误信息通过同一连接返回给 Web Server。FastCGI 子进程关闭连接时,就意味着请求处理完成了。之后,FastCGI 子进程会等待并处理来自 FastCGI 进程管理器(运行在 Web Server 中)的下一个连接。而在 CGI 模式中,php-cgi 在此就会退出。
在上述情况里,你能够想象到 CGI 通常是比较慢的。每一个 Web 请求,PHP 都得重新去解析 php.ini,重新载入全部的扩展,并且重新初始化全部的数据结构。而使用 FastCGI 的话,所有这些情况都仅仅在进程启动的时候发生一次。还有一个额外的好处,那就是持续数据库连接是可以工作的。
FastCGI的不足
多进程的情况会比 CGI 多线程消耗更多的服务器内存。PHP - CGI 解释器每进程会消耗 7 至 25 兆内存。将这个每进程消耗的内存数字分别乘以 50 或者 100,得到的就是很大的内存数。
Nginx 0.8.46 加上 PHP 5.2.14(FastCGI)构成的服务器,在面对 3 万并发连接时,开启的 10 个 Nginx 进程会消耗 150M 内存,因为 15M 乘以 10 等于 150M。同时,开启的 64 个 php-cgi 进程会消耗 1280M 内存,这是因为 20M 乘以 64 等于 1280M。再加上系统自身消耗的内存,总体消耗不到 2GB 内存。如果服务器的内存比较小,那么是完全可以仅仅开启 25 个 php-cgi 进程的。这样一来,php-cgi 所消耗的总的内存数量为 500M。
上面的数据是从 Nginx 0.8.x 与 PHP 5.2.13(FastCGI)搭建的 Web 服务器中摘取的,该服务器的性能胜过 Apache 十倍,这是第 6 版的内容。
PHP-CGI
PHP-CGI是PHP自带的FastCGI管理器。
PHP-CGI的不足:
php-cgi 变更了 php.ini 配置之后,需要重启 php-cgi 才能够让新的 php-ini 生效。并且,不能进行平滑重启。
如果直接杀死 php-cgi 进程,那么 php 就无法运行了。而 PHP-FPM 和 Spawn-FCGI 不存在这个问题,它们的守护进程能够平滑地重新生成新的子进程。
PHP-FPM
PHP-FPM 是一种 PHP FastCGI 管理器,它专门用于 PHP。它可以通过下载获取到。
PHP-FPM实际上是PHP源代码的一个补丁。它的目的是把FastCGI进程管理整合进PHP包里面。你需要将它patch到你的PHP源代码中,只有在编译安装PHP之后才能够使用它。
现在我们能够从最新的 PHP 5.3.2 的源码树中下载到直接整合了 PHP-FPM 的分支。据说下一个版本会将其融合进 PHP 的主分支。与 Spawn-FCGI 相比,PHP-FPM 在 CPU 控制方面更优秀,在内存控制方面也更出色。并且 Spawn-FCGI 很容易崩溃,必须使用 crontab 进行监控,而 PHP-FPM 没有这样的烦恼。
PHP5.3.3 已经将 php-fpm 集成其中,不再是第三方的包了。PHP-FPM 能够提供更优的 PHP 进程管理方式,它可以有效地控制内存和进程,还可以平滑地重载 PHP 配置。相比于 spawn-fcgi,PHP-FPM 具有更多的优点,正因如此,它被 PHP 官方收录了。在进行./configure 操作时,带上 –enable-fpm 参数,就可以开启 PHP-FPM。
Spawn-FCGI
然而,它存在不少缺点。PHP-FPM 的出现缓解了部分问题。不过,PHP-FPM 存在一个缺点,即需要重新编译。对于一些已经在运行的环境来说,这可能会带来不小的风险(refer)。在 php 5.3.3 中,能够直接使用 PHP-FPM 了。
Spawn-FCGI 如今已独立成为一个项目,它更为稳定,还为许多 Web 站点的配置带来了便利。已有不少站点把它与 nginx 搭配使用,以解决动态网页的问题。
最新的 lighttpd 不再包含这部分了。不过,在以前的版本中可以找到它。例如,在 lighttpd - 1.4.15 版本中就包含了这部分。目前,Spawn - FCGI 的下载地址是[具体地址],最新版本是[具体版本号]。
可以到 lighttpd.net 网站搜索“Spawn-FCGI”,从而找到最新的 Spawn-FCGI 的最新版本发布地址。
PHP-FPM与spawn-CGI对比
PHP-FPM 的使用较为便捷。其配置都在 PHP-FPM.ini 的文件当中。启动和重启能够通过 php/sbin/PHP-FPM 来进行。更为便利的是,在修改了 php.ini 之后,能够直接利用 PHP-FPM reload 进行加载,无需杀掉进程就可以完成对 php.ini 的修改加载。
结果显示,使用 PHP-FPM 能够给 php 带来较大的性能提升。PHP-FPM 所控制的进程,其 cpu 回收速度较为缓慢,而内存的分配则十分均匀。
Spawn-FCGI 控制的进程,其 CPU 下降速度很快,同时内存分配不太均匀。有许多进程好像没有分配到内存,而有些进程却占用量很高。或许是因为进程任务分配不均匀所导致的。这进而导致了总体响应速度的降低。而 PHP-FPM 能进行合理分配,使得总体响应得以提升,并且任务分配更加平均。
总结:
fastCGI 是用于 nginx 和 php 之间进行通信的接口。这个接口的实际处理过程是启动 php-fpm 进程来解析 php 脚本。也就是说,php-fpm 相当于一个动态应用服务器。通过这样的方式,就能够实现 nginx 对 php 的动态解析。因此,若 nginx 服务器要支持 php 解析,就需在 nginx.conf 里添加 php 的配置,即把 php 脚本转发到 fastCGI 进程监听的 IP 地址和端口(该端口在 php-fpm.conf 中已指定)。php 安装时,需要开启支持 fastCGI 的选项。需要编译安装 php-fpm 补丁或扩展。还需要启动 php-fpm 进程,这样才能解析 nginx 通过 fastCGI 转发过来的 php 脚本。