如何通俗地解释 CGI、FastCGI、php-fpm 之间的关系?

在apache里,可以以php5_module模块的方式调用PHP,而在nginx里面,则需要通过php-fpm来调用,这两种调用方式有什么不同?另外,它们跟cgi,fastcgi有什么关系?CGI:是 Web Server 与 Web Application 之间数据交换的一种

在apache里,可以以php5_module模块的方式调用PHP,

而在nginx里面,则需要通过php-fpm来调用,这两种调用方式有什么不同?

另外,它们跟cgi,fastcgi有什么关系?



  • 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 协议的接口程序,额外还提供了相对智能一些任务管理。




PHP 解释器的执行,主要有三者模式,mod_php、CGI、FastCGI


  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调度管理器,他们对其管理的方式也不一样




CGI是HTTP Server和一个独立的进程之间的协议,把HTTP Request的Header设置成进程的环境变量,HTTP Request的正文设置成进程的标准输入,而进程的标准输出就是HTTP Response包括Header和正文。

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. 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 协议的一个实现。