PHP 填坑记之 FastCGI 与 mod_php 详解

网上对于 FastCGI 与 mod_php 的知识比较杂乱而不全面,故在此整理一下,以便入门学习者查阅方便

背景

PHP最常用的方式是以模块的方式(mod_php)运行在 Apache 中,也是 Apache 运行 PHP 的默认方式;

但在 Nginx 中,Nginx 又使用的是 PHP-FPM ,但是 PHP-FPM 到底是个什么东东?跟 php 有什么关系?今天我们一起来探究一番

PHP处理器(PHP handlers)

首先需要记住的是,任何一种 Web 服务器(Apache、Nginx等)都是被设计成向用户发送html、图片等静态资源的,Web 服务器自身并不能解释任何动态脚本(PHP、Python等)

PHP 处理器就是用来解释 Web 应用中的 PHP 代码,并将它解释为 HTML 或其他静态资源,然后将解析的结果传给 Web 服务器,最后再由 Web 服务器发送给用户

大多数的 Web 服务器都不能解析 PHP 代码,因此它需要一个能解析 PHP 代码的程序,这就是 PHP 处理器

现在我们知道了,Apache 与Nginx 都需要 PHP 处理器来处理 php 代码,那么怎么连接上服务器与 php 处理器呢?也就是说服务器与 php 处理器如何通信?

答案是通过 SAPI(Server Application Programming Interface 服务器端应用编程端口),简单来说,SAPI 指的是 PHP 具体应用的编程接口, 就像 PC 一样,无论安装哪些操作系统,只要满足了 PC 的接口规范都可以在 PC 上正常运行, PHP 脚本要执行有很多种方式,通过 Web 服务器,或者直接在命令行下,也可以嵌入在其他程序中,有兴趣大家可以研究 PHP 内核

我们这里继续讨论 PHP 最常用的 SAPI 提供的 2 种连接方法:mod_php 和 mod_fastcgi

mod_php 模式

咱们回顾一下,Apache 是怎么能够识别 php 代码的?是不是 Apache 的配置文件 httpd.conf 中加上或者修改这样几句:

1
2
3
4
5
6
7
//添加
LoadModule php5_module modules/libphp5.so
AddType application/x-httpd-php .php
//修改
<IfModule dir_module>
DirectoryIndex index.php index.html index.htm index.html
</IfModule>

也即 php 作为 Apache 的一个子模块来运行,当通过 web 访问 php 文件时,Apache 就会调用 php5_module 来解析 php 代码

配置加载 mod_php 模块后,php 便是 Apahce 进程本身一部分,每个新的 Apache 子进程都会加载此模块

mod_fastcgi 模式

我们先看PHP-FPM官网的说明

PHP-FPM - A simple and robust FastCGI Process Manager for PHP
PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites.

PHP-FPM 是一个 PHP 的 FastCGI 进程管理器,解释的非常简单。这说明 PHP-FPM 是辅助 mod_fastcgi 模式进行工作的,然而 FastCGI 又是个什么东西?管理着什么进程?

什么是CGI?

CGI(Common Gateway Interface) 是WWW技术中最重要的技术之一,有着不可替代的重要地位

CGI 是外部应用程序( CGI 程序)与 Web 服务器之间的接口标准,是在 CGI 程序和 Web 服务器之间传递信息的规程

CGI 规范允许 Web 服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI 将 Web 的一组简单的静态超媒体文档变成一个完整的新的交互式媒体

说白了,CGI 是一种外部应用程序(CGI程序)与 Web 服务器的协议,CGI 是为了保证 Server 传递过来的数据是标准格式

什么是 FastCGI?

FastCGI 像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去 fork 一次(这是 CGI 最为人诟病的 fork-and-execute 模式)。它还支持分布式的运算, 即 FastCGI 程序可以在网站服务器以外的主机上执行并且接受来自其它网站服务器来的请求

FastCGI 是语言无关的、可伸缩架构的 CGI 开放扩展,其主要行为是将 CGI 解释器进程保持在内存中并因此获得较高的性能。众所周知,CGI 解释器的反复加载是 CGI 性能低下的主要原因,如果 CGI 解释器保持在内存中并接受 FastCGI 进程管理器调度,则可以提供良好的性能、伸缩性、Fail- Over 特性等等

一般情况下,FastCGI 的整个工作流程是这样的:

  1. Web Server 启动时载入 FastCGI 进程管理器(IIS ISAPI或 Apache Module)

  2. FastCGI 进程管理器自身初始化,启动多个 CGI 解释器进程(可见多个 php-cgi )并等待 WebServer 的连接

  3. 当客户端请求到达 Web Server 时,FastCGI 进程管理器选择并连接到一个 CGI 解释器。 Web server 将 CGI 环境变量和标准输入发送到 FastCGI 子进程 php-cgi

  4. FastCGI 子进程完成处理后将标准输出和错误信息从同一连接返回 Web Server。当 FastCGI 子进程关闭连接时,请求便告处理完成,FastCGI 子进程接着等待并处理来自 FastCGI 进程管理器(运行在 Web Server 中)的下一个连接,在 CGI 模式中,php-cgi 在此便已经退出

也就是说 FastCGI 是 CGI 的升级版,一种语言无关的协议,用来沟通程序(如 PHP, Python, Java)和Web服务器(Apache2, Nginx), 理论上任何语言编写的程序都可以通过 FastCGI 来提供 Web 服务

FastCGI 的特点是会在一个进程中依次完成多个请求,以达到提高效率的目的,大多数 FastCGI 实现都会维护一个进程池

通俗解释:FastCGI 事先就需要启动,而且可以启动多个 CGI 模块,在那里一直运行等着 web 发请求,然后再给 php 解析运算,完成后生成 html 返回给 web 后,但是完成后它不会退出,而是继续等着下一个 web 请求

PHP-FPM

PHP-FPM 就是针对于 PHP 的 FastCGI 的一种实现,他负责管理一个进程池,来处理来自 Web 服务器的请求

但是 PHP-FPM 仅仅是个“PHP FastCGI 进程管理器”, 它仍会调用 PHP 解释器本身来处理请求,PHP 解释器(在 Windows 下)就是 php-cgi.exe

结束语

说了这么多,也不知道是否表达清楚,如果有不正确的地方请指正,谢谢