关于 CGI 和 FastCGI 的理解
1. CGI的引入
在网站的整体架构中, Web Server (如 nginx, apache) 只是内容的分发者, 对客户端的请求进行应答.
若客户端请求的是 index.html 这类静态页面, 那么 Web Server 就去文件系统中找对应的文件, 找到返回给客户端 (一般是浏览器), 在这里 Web Server 分发的就是是静态数据.
若客户端请求的是 index.php 这类的动态页面请求, Web Server 根据配置文件知道这个不是静态文件, 则会调用 PHP 解析器 进行处理然后将返回的数据转发给客户端 (一般是浏览器), 在这里 Web Server 分发的就是是动态数据.
在这个过程中, Web Server 并不能直接处理静态或者动态请求, 对于静态请求是直接查找然后返回数据或者报错信息, 对于动态数据也是交付给其他的工具 (例如: PHP 解析器) 进行处理.
那么 Web Server 和处理工具 (例如: php-fpm) 是怎样进行交互的呢? 传输的是那些数据呢? 这些数据的格式又是怎样的呢?
由此便引出了今天的主角:
CGI
.
2. 关于 CGI
2.1 CGI 的概念
- CGI (Common Gateway Interface) 全称是 “通用网关接口”, 是一种让客户端 (web浏览器) 与Web服务器 (nginx等)程序进行通信 (数据传输)的协议. 用来规范 web 服务器传输到 PHP 解释器中的数据类型以及数据格式,
包括URL, 查询字符串、POST 数据, HTTP header 等, 也就是为了保证 web server 传递过来的数据是标准格式的.- CGI 可以用任何一种具有标准输入, 输出和环境变量的语言编写, 如 PHP, PERL、TCL 等. 不同类型语言写的程序只要符合 CGI 标准, 就能作为一个 CGI 程序与 web 服务器交互, 早期的 CGI 大多都是 C 或 C++ 编写的.
- 一般说的 CGI 指的是用各种语言编写的能实现该功能的程序.
2.2 CGI 程序的工作原理
- 每次当 web server 收到 index.php 这种类型的动态请求后, 会启动对应的 CGI 程序 (PHP 的解析器).
- PHP 解析器会解析 php.ini 配置文件, 初始化运行环境, 然后处理请求, 处理完成后将数据按照 CGI 规定的格式返回给 web server 然后退出进程.
- 最后 web server 再把结果返回给浏览器.
2.3 CGI 程序的特点
- 高并发时的性能较差:
CGI 程序的每一次 web 请求都会有启动和退出过程, 也就是最为人诟病的 fork-and-execute 模式 (每次HTTP服务器遇到动态请求时都需要重新启动脚本解析器来解析 php.ini, 重新载入全部 DLL 扩展并重初始化全部数据结构,
然后把结果返回给 HTTP 服务器), 很明显, 这样的接口方式会导致 PHP 的性能很差, 在处理高并发访问时, 几乎是不可用的.- 传统的 CGI 接口方式安全性较差.
- CGI 对 php.ini 的配置很敏感, 在开发和调试的时候相当方便.
2.4 CGI 程序的应用领域
- 因为 CGI 为每一次请求增加一个进程, 效率很低, 所以基本已经不在生产部署时采用. 但由于 CGI 对 PHP 配置的敏感性. 通常被用在开发和调试阶段.
3. 关于 FastCGI
3.1 FastCGI 的概念
通过 CGI 程序的工作原理可以看出: CGI 程序性能较差, 安全性较低, 为了解决这些问题产生了 FastCGI.
1. FastCGI (Fast Common Gateway Interface) 全称是 "快速通用网关接口".
是通用网关接口 (CGI) 的增强版本, 由 CGI 发展改进而来, 主要用来提高CGI程序性能, 类似于CGI,FastCGI 也是一种让交互程序与Web服务器通信的协议.
2. FastCGI 致力于减少网页服务器与 CGI 程序之间互动的开销, 从而使服务器可以同时处理更多的网页请求 (提高并发访问).
3. 同样的, 一般说的FastCGI指的也是用各种语言编写的能实现该功能的程序.
3.2 FastCGI 程序的工作原理
- Web Server 启动同时, 加载 FastCGI 进程管理器 ( Nginx 的 php-fpm 或者 IIS 的 ISAPI 或 Apache 的 Module).
- FastCGI 进程管理器读取 php.ini 配置文件, 对自身进行初始化, 启动多个CGI解释器进程 (php-cgi), 等待来自 Web Server 的连接.
- 当 Web Server 接收到客户端请求时, FastCGI 进程管理器选择并连接到一个 CGI 解释器. Web server 会将相关环境变量和标准输入发送到 FastCGI 子进程 php-cgi 进行处理.
- FastCGI 子进程完成处理后将数据按照 CGI 规定的格式返回给 Web Server, 然后关 FastCGI 子进程或者等待下一次请求.
3.3 FastCGI 对进程的管理方式
FastCGI 会先启一个 master, 解析配置文件, 初始化执行环境, 然后再启动多个 worker. 当请求过来时, master 会传递给一个 worker, 然后立即可以接受下一个请求. 这样就避免了重复的劳动, 效率自然提高. 而且当 worker 不够用时, master 可以根据配置预先启动几个 worker 等着;当然空闲 worker 太多时, 也会停掉一些, 这样就提高了性能, 也节约了资源. 这就是 FastCGI 的对进程的管理.
3.4 FastCGI 的特点
- FastCGI 具有语言无关性, 支持用大多数语言进行编写, 对应的程序也支持大多数主流的 web 服务器.
FastCGI 技术目前支持语言有: C/C++, Java, PHP, Perl, Tcl, Python, SmallTalk, Ruby 等.
支持 FastCGI 技术的主流 web 服务器有: Apache, Nginx, lighttpd 等.- FastCGI 程序的接口方式采用 C/S 结构, 可以将 web 服务器和脚本解析服务器分开, 独立于 web 服务器运行, 提高 web 服务器的并发性能和安全性.
提高性能: 这种方式支持多个 web 分发服务器和多个脚本解析服务器的分布式架构, 同时可以在脚本解析服务器上启动一个或者多个脚本解析守护进程来处理动态请求, 可以让 web
服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端, 这在很大程度上提高了整个应用系统的性能.
提高安全性: API方式把应用程序的代码与核心的 web 服务器链接在一起, 这时一个错误的 API 的应用程序可能会损坏其他应用程序或核心服务器, 恶意的API的应用程序代码甚至可以窃取另一个应用程序或核心服务器的密钥,
采用这种方式可以在很大程度上避免这个问题.- FastCGI 的不依赖于任何 Web 服务器的内部架构, 因此即使服务器技术的变化, FastCGI 依然稳定不变.
- FastCGI 程序在修改 php.ini 配置时可以进行平滑重启加载新配置. 所有的配置加载都只在FastCGI进程启动时发生一次, 每次修改 php.ini 配置文件, 只需要重启 FastCGI 程序
(php-fpm 等) 即可完成平滑加载新配置, 已有的动态请求会继续处理, 处理完成关闭进程, 新来的请求使用新加载的配置和变量进行处理.- FAST-CGI 是较新的标准, 架构上和 CGI 大为不同, 是用一个驻留内存的服务进程向网站服务器提供脚本服务. 像是一个常驻 (long-live) 型的 CGI, 维护的是一个进程池, 它可以一直执行着, 只要激活后, 不会每次都要花费时间去 fork 一次
(这是 CGI 最为人诟病的 fork-and-execute 模式), 速度和效率比 CGI 大为提高, 是目前的主流部署方式.- FastCGI 的不足: 因为是在内存中同时运行多进程, 所以会比 CGI 方式消耗更多的服务器内存, 每个 PHP-CGI 进程消耗 7 至 25 兆内存, 在进行优化配置 php-cgi 进程池的数量时要注意系统内存, 防止过量.
3.5 FastCGI 的特点 FastCGI 程序的应用领域
生产环境的主流部署方式.
4. 关于 CGI 和 FastCGI 的总结
- CGI 和 FastCGI 都只是一种通信协议规范, 不是一个实体, 一般说的CGI指的是用各种语言编写的能实现该功能的程序
- CGI 程序和 FastCGI 程序, 是指实现这两个协议的程序, 可以是任何语言实现这个协议的.(PHP-CGI 和 PHP-FPM就是实现FastCGI的程序)
- CGI 程序和 FastCGI 程序的区别:
关于 CGI 程序:
CGI 使外部程序与 Web 服务器之间交互成为可能. CGI 程序运行在独立的进程中, 并对每个Web 请求建立一个进程, 这种方法非常容易实现, 但效率很差, 难以扩展. 面对大量请求, 进程的大量建立和消亡使操作系统性能大大下降. 此外, 由于地址空间无法共享, 也限制了资源用.
关于 FastCGI程序:
与 CGI 程序为每个请求创建一个新的进程不同, FastCGI 使用持续的进程 (master) 来处理一连串的请求. 这些进程由 FastCGI 服务器管理, 而不是 web 服务器. 当进来一个请求时, web 服务器把环境变量和这个页面请求通过一个 socket 或者一个 TCP connection 传递给 FastCGI 进程.