• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • PHP SAPI:CGI、FastCGI、PHP-FPM

    SAPI(Server Application Programming Interface)服务器应用程序编程接口,即一个 PHP 与其他应用交互的接口,是应用程序与外部程序的通讯协议。PHP 脚本要执行有很多种方式,可以通过 Web 服务器,或者直接在命令行下执行,也可以嵌入在其他程序中。而 SAPI 在这里扮演的角色,则是提供了一个与外部应用(如 Nginx 服务器)通信的接口,使得 PHP 可以和其他应用进行交互数据。

    PHP 中常用的 SAPI 有 CGI、FastCGI、apache2handler、CLI 等。CLI 是命令行下执行 PHP 脚本的实现,它是单进程的,处理模型比较简单。而 CGI、FastCGI 相对比较复杂,它实现了网络处理模块,用于与 web 服务器交互。

    在 PHP 源码的/sapi目录下就是当前版本提供的 SAPI 列表:

    apache2handler/
    cgi/
    cli/
    embed/
    fpm/
    fuzzer/
    litespeed/
    phpdbg/
    

    编译后,在 centOS 假设安装执行程序目录为/usr/local/php/bin下就会存在,php、 php-cgi、php-fpm 三个可执行程序。在 window 操作系统下,是 php.exe, php-cgi.exe 文件。


    CGI 模式

    通常来自客户端的请求被 Web 服务器截获,如果是静态请求,则 Web 服务器(如:nginx)会自己做处理。如果是动态请求,则会抛给后端应用服务器(如:php-cgi)来处理。所以,如何在 web 服务器与应用服务器之间进行通信成了主要的问题,这也就是 SAPI 的作用。CGI 是就是其中一种 SAPI 规范,而php-cgi就是 CGI 的具体实现。

    CGI(Common Gateway Interface)是一种通用网关接口规范,该规范详细描述了 Web 服务器(如:nginx)和后端应用服务器(如:php-cgi)在获取及返回数据过程中传输数据的标准。(类似于 Web 浏览器和 Web 服务器进行数据交换的协议是 HTTP 协议)

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

    CGI 程序可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。CGI 的好处就是完全独立于任何服务器,仅仅是做为中间分子。例如,提供接口给 Nginx 和 php。他们通过 CGI 搭线来完成数据传递。这样做的好处就是尽量减少了这两个程序的关联,使他们变得更独立。


    FastCGI 模式

    FastCGI(Fast Common Gateway Interface)快速通用网关接口,是 CGI 的增强版本,为了提升 CGI 的性能而生。

    php-fpm(FastCGI Process Manager for PHP)PHP 的 FastCGI 进程管理器。FastCGI 只是一个协议规范,需要某个程序去具体实现,而 php-fpm 就是这个具体实现。

    在 CGI 模式中,CGI 程序(即 php-cgi)针对每个 HTTP 请求都会 fork 一个新的 php-cgi 进程来进行处理(解析配置文件、初始化执行环境、处理请求等),然后把这个进程处理完的结果通过 Web 服务器转发给客户端,这个 php-cgi 进程也随之退出。如果下次用户再请求动态资源,那么 CGI 程序又再次 fork 一个新的 php-cgi 进程,如此周而复始循环往复。我们也把这叫 fork-and-execute 模式,如果在大规模并发下,这种模式就会显得非常无力。

    而 FastCGI 模式中, FastCGI 程序(即 php-fpm)会先 fork 一个master进程,解析配置文件,初始化执行环境,然后再 fork 多个worker进程。 master 进程负责与 Web 服务器进行通信,当收到 HTTP 请求时, master 进程将其会传递给其中一个空闲的 worker 进程,然后立即可以继续接受下一个请求。这样就避免了重复的初始化操作,效率自然也就提高了。而且当 worker 进程不够用时, master 进程还可以根据配置预先启动几个 worker 进程等着;当空闲 worker 进程太多时,也会关掉一些,这样不仅提高了性能,还节约了系统资源。 worker 进程主要负责调用 Zend 虚拟机编译并执行 PHP 脚本的代码,处理完成后,再将处理结果返回给 Web 服务器。

    Linux 下查看 php-fpm 的进程情况如下,第一个是 master 进程,下面的是 worker 进程。

    ps aux | grep fpm
    
    显示如下:
    root         311  0.0  0.0  80748 10292 ?        Ss   21:15   0:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)
    www          317  0.0  0.0  82560 12028 ?        S    21:15   0:00 php-fpm: pool www
    www          318  0.0  0.0  82560 12028 ?        S    21:15   0:00 php-fpm: pool www
    root         485  0.0  0.0   6404  2172 pts/0    S+   22:05   0:00 grep --color=auto fpm
    

    详细步骤:
    1)Web 服务器(Nginx)启动时载入 FastCGI 进程管理器(PHP-FPM),FastCGI 进程管理器自身初始化,启动多个 CGI 解释器进程(php-cgi),并等待来自 Web Server 的连接。
    2)当收到 Web 服务器请求时,FastCGI 进程管理器选择并连接到一个 CGI 解释器。Web 服务器将 CGI 环境变量和标准输入发送到 FastCGI 子进程 php-cgi。
    3)FastCGI 子进程完成处理后,将标准输出和错误信息从同一连接返回给 Web 服务器。当 FastCGI 子进程关闭连接时,即该请求处理完成。(在CGI模式中,php-cgi 在此便退出了)
    4)FastCGI 子进程接着等待,并处理来自 FastCGI 进程管理器的下一个连接。

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

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


    CGI 与 FastCGI 的区别

    1)CGI 模式中,直接杀死 php-cgi 进程,php就不能运行了。FastCGI 模式就没有这个问题,守护进程会平滑重新生成新的 php-cgi 子进程。)
    2)对于 CGI 来说,每一个 Web 请求 PHP 都必须重新解析 php.ini、重新载入全部扩展,并重新初始化全部数据结构。而使用 FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。
    3)修改 php.ini 之后,php-cgi 进程无法平滑重启。php-fpm 对此的处理机制是新的 worker 用新的配置,已经存在的 worker 处理完手上的活就不再接受新的请求并准备退出,通过这种机制来平滑过度。
    4)由于 FastCGI 是多进程,所以比 CGI 消耗更多的服务器内存。如每个 php-cgi 解释器进程消耗 7MB 至 25MB 内存,将这个数字乘以 50 或 100 就是很大的内存数了。


    相关概念

    • 接口协议 SAPI:
      • CGI:(Common Gateway Interface)通用网关接口,是 Web Server 与 Web Application 之间数据交换的一种协议。
      • FastCGI:(Fast Common Gateway Interface)快速通用网关接口。同 CGI,是一种通信协议,但比 CGI 在效率上做了一些优化。
    • 接口程序:
      • PHP-CGI:是 PHP 对 Web Server 提供的 CGI 协议的接口程序。
      • PHP-FPM(FastCGI Process Manager):FastCGI 进程管理器,是 PHP 对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相对智能一些任务管理。
    • Web Server:一般指 Apache、Nginx、IIS、Lighttpd、Tomcat 等服务器。


    • PHP 运行模式:WEB 模式、CLI 模式。无论哪种模式,PHP 工作原理都是一样的,作为一种 SAPI 运行。
      • web 模式:当使用 Apache、Nginx、IIS、Lighttpd、Tomcat 等服务器服务器作为宿主时,当一个请求到来时,PHP 会来支持完成这个请求。一般有:多进程、多线程模式。
      • cli 模式:当我们在命令行终端敲入php xxx命令的时候,它使用的是 CLI 模式。它就像一个 web 服务器一样来支持 php 完成这个请求,请求完成后再重新把控制权交给终端。
    • Zend 引擎:是 PHP 语言实现的最为重要的部分,是PHP最基础、最核心的部分,它的源码在/Zend目录下。PHP 代码从编译到执行都是由 Zend 完成的。Zend 整体由两个部分组成:
      • 编译器:负责将 PHP 代码编译为抽象语法树,然后进一步编译为可执行的 opcodes,这个过程相当于 gcc 的工作,编译器是一个语言实现的基础。
      • 执行器:负责执行编译器输出的 opcodes,也就是执行 PHP 脚本中编写的代码逻辑。