SAPI运行生命周期

@bruce  July 28, 2020

SAPI

SAPI指的是Server Application Programming Interface服务端应用编程端口,它是PHP与其他应用交互的接口。PHP脚本要执行有许多方式,直接在命令行下运行,或通过Web服务器,也可以嵌入其他程序中。SAPI提供了一个和外部通信的接口,常见的SAPI有:Cli, CGI,FastCGI。

Cli

PHP的命令行运行模式。

CGI

CGI即通用网关接口(common gatewag interface),它是一段程序,通俗的讲CGI就象是一座桥,把网页和Web服务器中的执行程序连接起来,它把客户端请求传递给服务器的执行程序(PHP-CGI),再把服务器执行程序的结果返还给客户端。CGI方式在遇到客户端连接请求时先要创建CGI的子进程,激活一个CGI进程,然后处理请求,处理完后结束这个子进程。这就是fork-and-execute模式。所以用CGI方式的服务器有多少连接请求就会有多少CGI子进程,子进程反复加载是CGI性能低下的主要原因。当用户请求数量非常多时,会大量挤占系统的资源如内存和CPU等,造成效能低下。

FastCGI

FastCGI是CGI的升级版本,FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次。PHP使用PHP-FPM(FastCGI Process Manager),全称PHP FastCGI进程管理器进行管理。

Web服务器启动时载入FastCGI进程管理器,FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自Web服务器的连接。当客户端请求到达Web服务器时,FastCGI进程管理器选择并连接到一个CGI解释器。Web服务器将CGI环境变量和标准输入发送到FastCGI子进程PHP-CGI。FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web服务器。当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。在CGI模式中,PHP-CGI在此便退出了。

在上述情况中,你可以想象CGI通常有多慢。每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展并重初始化全部数据结构。使用FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。

SAPI运行PHP生命周期

不管何种SAPI,都会经过下面几个阶段( 可重复某几个环节):

  1. 模块初始化(Module init):调用每个拓展中的的PHP_MINIT_FUNCTION中的方法初始化模块,进行一些模块所需变量的申请,内存分配等。
  2. 请求初始化(Request init):接受到客户端的请求后调用每个拓展的PHP_RINIT_FUNCTION中的方法,初始化PHP脚本的执行环境,如Session模块的RINIT会初始化$_SESSION变量。
  3. 执行PHP脚本
  4. 请求结束(Request Shutdown):调用每个拓展的PHP_RSHUTDOWN_FUNCTION方法清理请求现场,并且Zend Engine开始回收变量和内存。
  5. 关闭模块(Module shutdown):Web服务器退出或者命令行脚本执行完毕退出会调用拓展源码中的PHP_MSHUTDOWN_FUNCTION 方法。
对于FastCGI,每个CGI子进程都会经过模块初始化和请求结束环节,不过每个子进程的模块初始化只在进程fork出来以来后进行,整个子进程的生命周期内可能会处理多个请求。只有在Web服务器退出或者子进程被结束之后才会进行关闭模块阶段,在这两个阶段之间会随着每个请求重复请求初始化-请求结束的环节。

添加新评论