CGI、FastCGI和PHP-FPM关系图解

36.4k PHP教程 , , 61评论

在搭建 LAMP/LNMP 服务器时,会经常遇到 PHP-FPM、FastCGI和CGI 这几个概念。如果对它们一知半解,很难搭建出高性能的服务器。接下来我们就以图形方式,解释这些概念之间的关系。

基础

在整个网站架构中,Web Server(如Apache)只是内容的分发者。举个栗子,如果客户端请求的是 index.html,那么Web Server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。

如果请求的是 index.php,根据配置文件,Web Server知道这个不是静态文件,需要去找 PHP 解析器来处理,那么他会把这个请求简单处理,然后交给PHP解析器。

当Web Server收到 index.php 这个请求后,会启动对应的 CGI 程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程,Web server再把结果返回给浏览器。这就是一个完整的动态PHP Web访问流程,接下来再引出这些概念,就好理解多了,

  • CGI:是 Web Server 与 Web Application 之间数据交换的一种协议。
  • FastCGI:同 CGI,是一种通信协议,但比 CGI 在效率上做了一些优化。同样,SCGI 协议与 FastCGI 类似。
  • PHP-CGI:是 PHP (Web Application)对 Web Server 提供的 CGI 协议的接口程序。
  • PHP-FPM:是 PHP(Web Application)对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相对智能一些任务管理。

WEB 中,

  • Web Server 一般指Apache、Nginx、IIS、Lighttpd、Tomcat等服务器,
  • Web Application 一般指PHP、Java、Asp.net等应用程序。

Module方式

在了解 CGI 之前,我们先了解一下Web server 传递数据的另外一种方法:PHP Module加载方式。以 Apache 为例,在PHP Module方式中,是不是在 Apache 的配置文件 httpd.conf 中加上这样几句:

# 加入以下2句
LoadModule php5_module D:/php/php5apache2_2.dll
AddType application/x-httpd-php .php

# 修改如下内容
<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>

上面是 Windows 下安装php和apache环境后手动配置,在linux下源码安装大致是这样配置的:

# ./configure --with-mysql=/usr/local --with-apache=/usr/local/apache --enable-track-vars

所以,这种方式,他们的共同本质都是用 LoadModule 来加载 php5_module,就是把php作为apache的一个子模块来运行。当通过web访问php文件时,apache就会调用php5_module来解析php代码。

那么php5_module是怎么来将数据传给php解析器来解析php代码的呢?答案是通过sapi。

我们再来看一张图,详细的说说apache 与 php 与 sapi的关系:

mode_php

从上面图中,我们看出了sapi就是这样的一个中间过程,SAPI提供了一个和外部通信的接口,有点类似于socket,使得PHP可以和其他应用进行交互数据(apache,nginx等)。php默认提供了很多种SAPI,常见的提供给apache和nginx的php5_module、CGI、FastCGI,给IIS的ISAPI,以及Shell的CLI。

所以,以上的apache调用php执行的过程如下:

apache -> httpd -> php5_module -> sapi -> php

好了。apache与php通过php5_module的方式就搞清楚了吧!

这种模式将php模块安装到apache中,所以每一次apache结束请求,都会产生一条进程,这个进程就完整的包括php的各种运算计算等操作。

在上图中,我们很清晰的可以看到,apache每接收一个请求,都会产生一个进程来连接php通过sapi来完成请求,可想而知,如果一旦用户过多,并发数过多,服务器就会承受不住了。

而且,把mod_php编进apache时,出问题时很难定位是php的问题还是apache的问题。

CGI

CGI(Common Gateway Interface)全称是“通用网关接口”,WEB 服务器与PHP应用进行“交谈”的一种工具,其程序须运行在网络服务器上。CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php、perl、tcl等。

WEB服务器会传哪些数据给PHP解析器呢?URL、查询字符串、POST数据、HTTP header都会有。所以,CGI就是规定要传哪些数据,以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在PHP代码中使用的用户从哪里来的。

也就是说,CGI就是专门用来和 web 服务器打交道的。web服务器收到用户请求,就会把请求提交给cgi程序(如php-cgi),cgi程序根据请求提交的参数作应处理(解析php),然后输出标准的html语句,返回给web服服务器,WEB服务器再返回给客户端,这就是普通cgi的工作原理。

CGI的好处就是完全独立于任何服务器,仅仅是做为中间分子。提供接口给apache和php。他们通过cgi搭线来完成数据传递。这样做的好处了尽量减少2个的关联,使他们2变得更独立。

但是CGI有个蛋疼的地方,就是每一次web请求都会有启动和退出过程,也就是最为人诟病的fork-and-execute模式,这样一在大规模并发下,就死翘翘了。

FastCGI介绍

FastCGI简单介绍

从根本上来说,FastCGI是用来提高CGI程序性能的。类似于CGI,FastCGI也可以说是一种协议

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

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

FastCGI的工作原理

FastCGI接口方式采用C/S结构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给浏览器。这种方式可以让HTTP服务器专一地处理静态请求,或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。

fastcgi

  1. Web Server启动时载入FastCGI进程管理器(Apache Module或IIS ISAPI等)
  2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可建多个php-cgi),并等待来自Web Server的连接。
  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特点:

  1. 对于CGI来说,每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展,并重新初始化全部数据结构。而使用FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。
  2. 由于FastCGI是多进程,所以比CGI多线程消耗更多的服务器内存,php-cgi解释器每进程消耗7至25兆内存,将这个数字乘以50或100就是很大的内存数。

PHP-FPM介绍

要了解PHP-FPM,就得先说说PHP-CGI。

PHP-CGI就是PHP实现的自带的FastCGI管理器。 虽然是php官方出品,但是这丫的却一点也不给力,性能太差,而且也很麻烦不人性化,主要体现在:

  1. php-cgi变更php.ini配置后,需重启php-cgi才能让新的php-ini生效,不可以平滑重启。
  2. 直接杀死php-cgi进程,php就不能运行了。

上面2个问题,一直让很多人病垢了很久,所以很多人一直还是在用 Module 方式。 直到 2004年一个叫 Andrei Nigmatulin的屌丝发明了PHP-FPM ,这神器的出现就彻底打破了这种局面,这是一个PHP专用的 fastcgi 管理器,它很爽的克服了上面2个问题,而且,还表现在其他方面更表现强劲。

也就是说,PHP-FPM 是对于 FastCGI 协议的具体实现,他负责管理一个进程池,来处理来自Web服务器的请求。目前,PHP5.3版本之后,PHP-FPM是内置于PHP的

因为PHP-CGI只是个CGI程序,他自己本身只能解析请求,返回结果,不会进程管理。所以就出现了一些能够调度 php-cgi 进程的程序,比如说由lighthttpd分离出来的spawn-fcgi。同样,PHP-FPM也是用于调度管理PHP解析器php-cgi的管理程序。

PHP-FPM通过生成新的子进程可以实现php.ini修改后的平滑重启。

总结

最后,我们来总结一下,这些技术经过不断的升级,可以解决什么问题(不然也不会升级嘛)。

所以,如果要搭建一个高性能的PHP WEB服务器,目前最佳的方式是Apache/Nginx + FastCGI + PHP-FPM(+PHP-CGI)方式了,不要再使用 Module加载或者 CGI 方式啦:)

本文章图片用Visio制作,源文件:php-fpm

参考资料

  1. 概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM:http://www.nowamagic.net/librarys/veda/detail/1319
  2. php中fastcgi和php-fpm是什么东西:https://www.zybuluo.com/phper/note/50231
  3. 请问CGI、PHP-CGI、PHP-FPM之间是什么关系?https://groups.google.com/forum/?fromgroups=#!topic/shlug/d5hJKyFzI-g
  4. FastCGI 进程管理器(FPM):http://php.net/manual/zh/install.fpm.php

 

61 条评论

程序员 says: 回复

可以转发吗

歪麦 says: 作者

可以的,标示一下本文地址就好了。

程序员 says:

谢谢

3
3maio says: 回复

您好,是否可以交换友链?

j
joker says: 回复

牛逼,讲解的非常清楚。

小周 says: 回复

你好,文章中提到。目前,PHP5.3版本之后,PHP-FPM是内置于PHP的,为什么lamp的时候还需另外安装PHP,LNMP的时候安装了PHP-FPM之后就不需要安装PHP,我猜想是PHP-FPM是内置于PHP,所以安装PHP-FPM的时候就必须要先安装PHP,所以才不需要单独安装PHP。我不知道猜想对不对。能给我解释下吗?谢谢

歪麦 says: 作者

LAMP安装之后还需另外安装PHP?LAMP中的P不就是PHP么?

Q
QShaw says: 回复

所以为什么现在大部分的LAMP还是以Module方式运行的?这里面性能的差异究竟有多大?是因为配置PHP-FPM在apache里配置太复杂,并且大部分小型站点在性能差异上体现并不明显,还是什么别的原因呢?或者是我用的LAMP安装包过时了?

歪麦 says: 作者

在高并发的时候体现明显

l
lll says: 回复

写的这是啥 和http://www.thinkphp.cn/topic/42338.html几乎都存在相同的问题, 繁琐, 矛盾, 最大的问题就是矛盾

“PHP-CGI:是 PHP (Web Application)对 Web Server 提供的 CGI 协议的接口程序。” 这里说实现了CGI协议

下面又说 “PHP-CGI就是PHP实现的自带的FastCGI管理器。”

PHP-CGI到底是实现了FastCGI协议 还是 CGI协议? 还是说是来管理实现了FastCGI协议的程序?

p
peng says:

那正确的哪里可以找的到呢。是怎么样的流程。初级php 看不懂呐

替天行道 says:

看不懂,你就瞎J8转,瞎J8写,误导多少人。

测试 says:

cgi是协议,php-cgi是实现这种协议的程序。

i
imzhi says:

CGI 是 Web Server 与 Web Application 之间数据交换的一种协议。
FastCGI 同 CGI 是一种通信协议,但比 CGI 在效率上做了一些优化,同样 SCGI 协议与 FastCGI 类似。
PHP-CGI 是 PHP (Web Application)对 Web Server 提供的 CGI 协议的接口程序。
PHP-FPM 是 PHP(Web Application)对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相信智能一些任务管理。

D
DK says: 回复

FastCGI与CGI特点:
…重新载入全部扩展,并重初始化全部数据结构

上面少了个字:“重新载入全部扩展,并重 新 初始化全部数据结构”

歪麦 says: 作者

感谢提醒。

若疯 says: 回复

sapi又是什么

陈帅同学 says: 回复

博主写的通俗易懂, 支持一下
另外,可以转载吗?
可以交换友链吗?

歪麦 says: 作者

转载注明原文地址。

m
moyu says: 回复

PHP-CGI就是PHP实现的自带的FastCGI管理器,这句是错误的,我之前看到有人提问这个问题,原来是你这里传出去的。。php-cgi是php实现CGI的php解释器,php-fpm才是实现fastcgi的进程管理器

无名氏 says:

楼主没错,错的是你,php-cgi(就是php安装目录下,那个叫`php-cgi`的可执行程序,在windows下叫`php-cgi.exe`)就是php官方开发并实现了fastCGI协议的一个工具,它与php-fpm有类似功能,只不过没有php-fpm优秀,所以后来都用php-fpm了。

证明php-cgi是实现fastcgi协议的一个工具:请到php目录下找到php-cgi,运行./php-cgi -v (如果windows你就直接运行php-cgi.exe -v),看一下输出的内容,明确写着『cgi-fcgi』

PHP 7.2.9 (cgi-fcgi) (built: Aug 23 2018 02:08:52)
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans
with Zend OPcache v7.2.9, Copyright (c) 1999-2018, by Zend Technologies

d
david shen says:

我赞同你,并且我可以证明,
PHP-CGI就是PHP实现的自带的FastCGI管理器,这句是错误的,证明很简单
在终端敲:man php-cgi

打印结果:
php – PHP Command Line Interface ‘CLI’
php-cgi – PHP Common Gateway Interface ‘CGI’ command

所以,不需要任何解释了,很清楚。

无名氏 says: 回复

请问『PHP-CGI就是PHP实现的自带的FastCGI管理器』是怎么证明的?网上有官方的资料吗?还是用技术的方式证明?因为有人说这php-cgi就是实现的cgi而不是fastcgi。

w
wwwphper says: 回复

php-cgi实现的是fastcgi协议,源码sapi目录下cgi_main.c里.
参考文章http://www.php-internals.com/book/?p=chapt02/02-02-03-fastcgi

d
david shen says: 回复

PHP-CGI就是PHP实现的自带的FastCGI管理器,这句是错误的,证明很简单
在终端敲:man php-cgi

打印结果:
php – PHP Command Line Interface ‘CLI’
php-cgi – PHP Common Gateway Interface ‘CGI’ command

所以,不需要任何解释了,很清楚。

l
lanco says: 回复

如果去看源码就清楚所谓的php-cgi到底是什么,何必争议,PHP源码会骗你吗

靓仔 says: 回复

学习了 我感觉我又悟了 \(^o^)/~

k
kc says: 回复

Apache Module 不是一个进程管理器么?

L
Lis says: 回复

PHP-CGI就是PHP实现的自带的FastCGI管理器,这句是错误的.这只是PHP实现的CGI解析程序。PHP源码如下
https://github.com/php/php-src/blob/master/sapi/cgi/cgi_main.c#L1714
PHP-FPM(FastCGI Process Manage)才是FastCGI管理器 ,源码如下
https://github.com/php/php-src/blob/master/sapi/fpm/fpm/fpm_main.c#L1510

d
d says:

确实如此, 这里似乎有些历史原因,容易造成混淆

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

昵称 *