FASTCGI是和HTTP协议类似的概念。无非就是规定了在同一个TCP连接里怎么同时传多个HTTP连接。这实际上导致了个问题,有个HTTP连接传个大文件不肯让出FASTCGI连接,在同一个FASTCGI连接里的其他HTTP连接就傻了。所以Lighttpd? 引入了 X-SENDFILE 。
php-fpm就相当于是Apache+mod_php。无非php-fpm自带了FASTCGI Server,而Apache是HTTP Server。
那个WSGI和这个问题没啥关系吧。WSGI这个只是Python内部的一个接口。无论你前面是FASTCGI,HTTP,SCGI,uWSGI等协议,你的FASTCGI/HTTP/SCGI/uWSGI Server都以相同的参数格式去调用一个函数,这样你用Python写的Web应用并不需要修改代码,就可以运行在不同的Server后面了。无非CGI协议是进程间的,而WSGI是进程内的。
1. 一般web服务器接受到浏览器的请求时,如果是静态资源的话就直接将其返回给浏览器,如果是动态资源的话那就没有现成的资源返回了,那这个时候cgi就出场了
2. cgi可以理解为一种协议or一类处理程序,就是动态去生成文件,从程序上来理解就是web服务器exec这样一个进程,然后交给他一些输入参数,他就慢慢的处理完后把结果返回给web服务器,那从协议层面来说cgi协议就是规范了web服务器和cgi程序的一些输入输出参数的含义
3.所以可以有很多不同的cgi程序,别可以执行php脚本的or可以执行python脚本的,只要符合这类规范就能供web服务器调用,当然它的缺点就是每次都需要去启动这个cgi程序,这会使得处理速度很慢
4.针对这种缺陷加以改进就成了fastcgi,同样的他也可以理解为一种协议or一个程序,它跟cgi的不同就是不需要每次去exec,它会事先启动起来,作为一个cgi的管理服务器存在,预先启动一系列的子进程来等待处理,然后等待web服务器发过来的请求,一旦接受到请求就交由子进程处理,这样由于不需要在接受到请求后启动cgi,会快很多。
5.phpfpm是php对fastcgi的一种具体实现,它的启动后会创建多个cgi子进程,然后主进程负责管理子进程,同时它对外提供一个socket,那web服务器当要转发一个动态请求时只需要按照fastcgi协议要求的格式将数据发往这个socket的就可以了,那phpfpm创建的子进程去争抢这个socket连接,谁抢到了谁处理并将结果返回给web服务器,那phpfpm主进程干什么了?比方说其中一个子进程异常退出了怎么办,那phpfpm会去监控他一旦发现一个cgi子进程就会又启动一个,还有其他诸多管理功能
6 phpfpm作为一个独立的进程存在 通过socket与nginx建立连接,而mod_php 是作为一个模块被加载进了apache服务器,同时他们两作为cgi调度管理器,他们对其管理的方式也不一样
通俗的说法
通俗的可以把服务器看作餐厅,用户请求看作来用餐的顾客,服务器处理请求看作解决顾客的就餐问题(响应输出一份饭)。
服务器上静态资源看作已做好的饭,只要放到餐盒里就可以返回给顾客,动态资源需要厨房大厨现成做份再放到餐盒里返回给顾客。
php_mod这个大厨有个特点,看见有顾客进门就点火,不管顾客要不要现做的,有点浪费资源
php_fpm这个大厨有好多小弟一直点着火(多个处理进程),等有顾客说要现做,大厨就安排小弟做份返回给客户
cgi也是个大厨,不过他等到顾客要现做,他才点火,做饭,然后熄火。等待下一个要现做的到来
fastcgi呢就是个大厨雇了一帮小弟,专门做需要现场做的饭,大厨只管分派任务,小弟真正操锅做饭
1. PHP 解释器是否嵌入 Web 服务器进程内部执行
mod_php 通过嵌入 PHP 解释器到 Apache 进程中,只能与 Apache 配合使用,而 cgi 和 fast-cgi 以独立的进程的形式出现,只要对应的Web服务器实现 cgi 或者 fast-cgi 协议,就能够处理 PHP 请求。
mod_php 这种嵌入的方式最大的弊端就是内存占用大,不论是否用到 PHP 解释器都会将其加载到内存中,典型的就是处理CSS、JS之类的静态文件是完全没有必要加载解释器。
2. 单个进程处理的请求数量
mod_php 和 fast-cgi 的模式在每个进程的生命周期内能够处理多个请求,而 cgi 的模式处理一个请求就马上销毁进程,在高并发的场景下 cgi 的性能非常糟糕。
综上,如果对性能有极高的要求,可以将静态请求和动态请求分开,这时 Nginx + php-fpm 是比较好的选择。
PS: cgi、fastcgi 通常指 Web 服务器与解释器通信的协议规范,而 php-fpm 是 fastcgi 协议的一个实现
CGI(Common Gateway Interface)
最初,CGI 是在 1993 年由美国国家超级电脑应用中心(NCSA)为 NCSA HTTPd Web 服务器开发的。
这个 Web 服务器使用了 UNIX shell 环境变量 来保存从 Web 服务器传递出去的参数,然后生成一个运行 CGI 的独立进程。CGI的第一个实现是 Perl 写的[1]。
- 效率低下:每一个连接 fork 一个进程处理。
- 功能十分有限:CGI只能收到一个请求,输出一个响应。很难在CGI体系去对Web请求的控制,例如:用户认证等。
正因为这些问题,在CGI诞生后的很长一段时间,各种Web Server都还是采用API这种强绑定的方式去支持Web开发,其中Apache的mod_php就属于这种方式。所以后面就有大神提出了FastCGI标准。
FastCGI(Fast Common Gateway Interface)
FastCGI使用进程/线程池来处理一连串的请求。这些进程/线程由FastCGI服务器管理,而不是Web服务器。 当进来一个请求时,Web服务器把环境变量和这个页面请求通过一个Socket长连接传递给FastCGI进程。所以FastCGI有如下的优点:
- 性能:通过进程/线程池规避了CGI开辟新的进程的开销。
- 兼容:非常容易改造现有CGI标准的程序。
- 语言无关:FastCGI是一套标准,理论上讲只要能进行标准输出(stdout)的语言都可以作为FastCGI标准的Web后端。
下面是一个简单FastCGI后端的伪代码
void main(void)
{
int count = 0;
while(FCGI_Accept() >= 0) {
printf(“Content-type: text/html\r\n”);
printf(“\r\n”);
printf(“Hello world!\r\n”);
printf(“Request number %d.”, count++);
}
exit(0);
}
- Web Server隔离:FastCGI后端和Web Server运行在不同的进程中,后端的任何故障不会导致Web Server挂掉。
- 专利:没有Apache mod_php之类的私有API的知识产权问题。
- 扩展:FastCGI后端和Web Server通过Socket进行通信,两者可以分布式部署并方便进行横向扩展。
所以FastCGI一推出就几乎获得了所有主流Web Server的支持,Apache、Lighttpd、IIS、Cherokee……
题主说的PHP-fpm就是一种FastCGI的后端实现。
But,事情总是还有改进的余地的,FastCGI这套工作模式实际上没有什么太大缺陷,但是有些不安分的Python程序猿觉得,FastCGI标准下写异步的Web服务还是不太方便,如果能够收到请求后CGI端去处理,处理完毕后通过Callback回调来返回结果,那样岂不是很Coooool?!所以WSGI就被创造出来了:
WSGI(Web Server Gateway Interface)
Web服务器网关接口(Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。
当Web Server收到一个请求后,可以通过Socket把环境变量和一个Callback回调函数传给后端Web应用,Web应用在完成页面组装后通过Callback把内容返回给Web Server。这样做的优点有很多:
- 异步化,通过Callback将Web请求的工作拆解开,可以很方便的在一个线程空间里同时处理多个Web请求。
- 方便进行各种负载均衡和请求转发,不会造成后端Web应用阻塞。
- mode_php 是Apache 的一个模块,把PHP 解释器嵌入到Apache 进程中。
- CGI 和FastCGI 分别是一种协议。Web Server 实现了CGI 或FastCGI 协议的相应的应用程序(以下简称CGI 或FastCGI),就可以启动PHP 解释器处理PHP 请求。它们都是以独立进程的形式存在。
- mode_php 和FastCGI 在 单个进程中可以处理多个请求,CGI 在单个进程中只能处理一个请求。
php-cgi 是一种CGI 协议的实现。
- php-cgi 其实就是PHP 解析器。
- 在CGI 模式时,当Web Server 收到 xx/index.php 请求时,会启动php-cgi,php-cgi 会解析php.ini 文件,初始化环境,然后根据请求参数进行处理,再返回处理后的结果。(都是以CGI 协议规范来进行)
- php-cgi 在每个请求时都会启动一个进程,然后读取php.ini 进行解析,可想而知效率相对比较低。
- php-cgi 无法实现平滑重启。修改php.ini 配置后,后面启动的php-cgi 程序还是不会感知。
FastCGI根据协议将CGI进行包装,与外部程序如nginx进行通信。一般拥有主从进程。FastCGI可以管理多种语言的CGI,比如题主提到的PHP,另外还有Python、Ruby等。可以理解为一种CGI的成熟模型。
而PHP-FPM是一个很好地实现了FastCGI的程序,后来被PHP收入官方项目中了。可以理解为FastCGI的管理器。稳定地管理FastCGI进程。