CGI、FastCGI和PHP-FPM关系图解
在搭建LAMP/LNMP服务器时,会经常遇到 PHP-FPM、FastCGI和CGI这几个概念。如果对它们一知半解,很难搭建出高性能的服务器。接下来我们就以图形方式,解释这些概念之间的关系。
基础
在整个网站架构中,WebServer(如Apache)只是内容的分发者。举个栗子,如果客户端请求的是index.html,那么WebServer会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。
如果请求的是index.php,根据配置文件,WebServer知道这个不是静态文件,需要去找PHP解析器来处理,那么他会把这个请求简单处理,然后交给PHP解析器。
当WebServer收到index.php这个请求后,会启动对应的CGI程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程,Webserver再把结果返回给浏览器。这就是一个完整的动态PHPWeb访问流程,接下来再引出这些概念,就好理解多了,
- CGI:是WebServer与WebApplication之间数据交换的一种协议。
- FastCGI:同CGI,是一种通信协议,但比CGI在效率上做了一些优化。同样,SCGI协议与FastCGI类似。
- PHP-CGI:是PHP(WebApplication)对WebServer提供的CGI协议的接口程序。
- PHP-FPM:是PHP(WebApplication)对WebServer提供的FastCGI协议的接口程序,额外还提供了相对智能一些任务管理。
WEB中,
- WebServer一般指Apache、Nginx、IIS、Lighttpd、Tomcat等服务器,
- WebApplication一般指PHP、Java、Asp.net等应用程序。
Module方式
在了解CGI之前,我们先了解一下Webserver传递数据的另外一种方法:PHPModule加载方式。以Apache为例,在PHPModule方式中,是不是在Apache的配置文件httpd.conf中加上这样几句:
#加入以下2句 LoadModulephp5_moduleD:/php/php5apache2_2.dll AddTypeapplication/x-httpd-php.php #修改如下内容 <IfModuledir_module> DirectoryIndexindex.phpindex.html </IfModule>
上面是Windows下安装php和apache环境后手动配置,在linux下源码安装大致是这样配置的:
#./configure--with-mysql=/usr/local--with-apache=/usr/local/apache--enable-track-vars
CGI
CGI(CommonGatewayInterface)全称是“通用网关接口”,WEB服务器与PHP应用进行“交谈”的一种工具,其程序须运行在网络服务器上。CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php、perl、tcl等。
WEB服务器会传哪些数据给PHP解析器呢?URL、查询字符串、POST数据、HTTPheader都会有。所以,CGI就是规定要传哪些数据,以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在PHP代码中使用的用户从哪里来的。
但是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服务器专一地处理静态请求,或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。
- WebServer启动时载入FastCGI进程管理器(ApacheModule或IISISAPI等)
- FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可建多个php-cgi),并等待来自WebServer的连接。
- 当客户端请求到达WebServer时,FastCGI进程管理器选择并连接到一个CGI解释器。Webserver将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。
- FastCGI子进程完成处理后,将标准输出和错误信息从同一连接返回WebServer。当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待,并处理来自FastCGI进程管理器(运行在WebServer中)的下一个连接。在CGI模式中,php-cgi在此便退出了。
FastCGI与CGI特点:
- 对于CGI来说,每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展,并重新初始化全部数据结构。而使用FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistentdatabaseconnection)可以工作。
- 由于FastCGI是多进程,所以比CGI多线程消耗更多的服务器内存,php-cgi解释器每进程消耗7至25兆内存,将这个数字乘以50或100就是很大的内存数。
PHP-FPM介绍
要了解PHP-FPM,就得先说说PHP-CGI。
PHP-CGI就是PHP实现的自带的FastCGI管理器。虽然是php官方出品,但是这丫的却一点也不给力,性能太差,而且也很麻烦不人性化,主要体现在:
- php-cgi变更php.ini配置后,需重启php-cgi才能让新的php-ini生效,不可以平滑重启。
- 直接杀死php-cgi进程,php就不能运行了。
上面2个问题,一直让很多人病垢了很久,所以很多人一直还是在用 Module 方式。直到2004年一个叫AndreiNigmatulin的屌丝发明了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修改后的平滑重启。
总结
最后,我们来总结一下,这些技术经过不断的升级,可以解决什么问题(不然也不会升级嘛)。
所以,如果要搭建一个高性能的PHPWEB服务器,目前最佳的方式是Apache/Nginx+FastCGI+PHP-FPM(+PHP-CGI)方式了,不要再使用Module加载或者CGI方式啦:)
本文章图片用Visio制作,源文件:php-fpm
参考资料
- 概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM:http://www.nowamagic.net/librarys/veda/detail/1319
- php中fastcgi和php-fpm是什么东西:https://www.zybuluo.com/phper/note/50231
- 请问CGI、PHP-CGI、PHP-FPM之间是什么关系?https://groups.google.com/forum/?fromgroups=#!topic/shlug/d5hJKyFzI-g
- FastCGI进程管理器(FPM):http://php.net/manual/zh/install.fpm.php