基础概念PHP-FPM、FastCGI和CGI
在搭建 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的关系:
从上面图中,我们看出了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服务器专一地处理静态请求,或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。
- web server启动时载入fastcgi进程管理器(apache module或iis isapi等)
- 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在此便退出了。
fastcgi与cgi特点:
- 对于cgi来说,每一个web请求php都必须重新解析php.ini、重新载入全部扩展,并重新初始化全部数据结构。而使用fastcgi,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(persistent database connection)可以工作。
- 由于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年一个叫 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 方式啦:)
推荐阅读
-
PHP面试:简述CGI、FastCGI和PHP-FPM的区别
-
cgi、fastcgi及php-fpm分别是什么
-
php环境配置之CGI、FastCGI、PHP-CGI、PHP-FPM、Spawn-FCGI比较?
-
[python面向对象学习笔记一] 面向对象的概念和基础语法
-
php提供的sapi有哪些?CGI、FastCGI、php-fpm、php-cgi解释
-
基础概念PHP-FPM、FastCGI和CGI
-
MySQL数据库应用--数据库概念和SQL基础部分学习笔记整理
-
MongoDB入门系列(一):基础概念和安装
-
FPGA/verilog 学习笔记—— FPGA和HDL基础概念
-
CGI 和 FastCGI 协议的运行原理