目录php
在用PHP开发的过程当中,咱们经常使用Nginx或者Apache做为咱们的Web服务器。可是PHP是如何与这些Web服务器通讯的呢?nginx
Apache把PHP做为一个模块集成到Apache进程(httpd)运行,这种mod_php的运行模式与PHP-CGI没有任何关系。web
Nginx是经过FastCGI
来实现与PHP的通讯。数据库
要谈FastCGI就必须先说说CGI。那什么是CGI?编程
CGI(
Common Gateway Interface:通用网关接口
)是Web 服务器运行时外部程序的规范,按CGI 编写的程序能够扩展服务器功能。CGI 应用程序能与浏览器进行交互,还可经过数据库API 与数据库服务器等外部数据源进行通讯,从数据库服务器中获取数据。--百度百科浏览器
CGI协议
同 HTTP 协议同样是一个「应用层」协议,它的 功能 是为了解决 Web 服务器与 PHP 应用(或其余 Web 应用)之间的通讯问题。服务器
既然它是一个「协议」,换言之它与语言无关,即只要是实现类 CGI 协议的应用就可以实现相互的通讯。网络
咱们已经知道了 CGI 协议是为了完成 Web 服务器和应用之间进行数据通讯这个问题。那么,这一节咱们就来看看究竟它们之间是如何进行通讯的。架构
简单来说 CGI 协议它描述了 Web 服务器和应用程序之间进行数据传输的格式,而且只要咱们的编程语言支持标准输入(STDIN)、标准输出(STDOUT)以及环境变量等处理,你就可使用它来编写一个 CGI 程序。并发
当用户访问咱们的 Web 应用时,会发起一个 HTTP 请求。最终 Web 服务器接收到这个请求。
Web 服务器建立一个新的 CGI 进程。在这个进程中,将 HTTP 请求数据已必定格式解析出来,并经过标准输入和环境变量传入到 URL 指定的 CGI 程序(PHP 应用 $_SERVER)。
Web 应用程序处理完成后将返回数据写入到标准输出中,Web 服务器进程则从标准输出流中读取到响应,并采用 HTTP 协议返回给用户响应。
一句话就是 Web 服务器中的 CGI 进程将接收到的 HTTP 请求数据读取到环境变量中,经过标准输入转发给 PHP 的 CGI 程序;当 PHP 程序处理完成后,Web 服务器中的 CGI 进程从标准输出中读取返回数据,并转换回 HTTP 响应消息格式,最终将页面呈献给用户。而后 Web 服务器关闭掉这个 CGI 进程。
能够说 CGI 协议特别擅长处理 Web 服务器和 Web 应用的通讯问题。然而,它有一个严重缺陷,对于每一个请求都须要从新 fork 出一个 CGI 进程,处理完成后当即关闭。
每次处理用户请求,都须要从新 fork CGI 子进程、销毁 CGI 子进程。
一系列的 I/O 开销下降了网络的吞吐量,形成了资源的浪费,在大并发时会产生严重的性能问题。
从功能上来说,CGI
协议已经彻底可以解决 Web 服务器与 Web 应用之间的数据通讯问题。可是因为每一个请求都须要从新 fork 出 CGI 子进程致使性能堪忧,因此基于 CGI
协议的基础上作了改进便有了 FastCGI
协议,它是一种常驻型的 CGI 协议。
本质上来将 FastCGI 和 CGI 协议几乎彻底同样,它们均可以从 Web 服务器里接收到相同的数据,不一样之处在于采起了不一样的通讯方式。
再来回顾一下 CGI 协议每次接收到 HTTP 请求时,都须要经历 fork 出 CGI 子进程、执行处理并销毁 CGI 子进程这一系列工做。
而 FastCGI
协议采用 进程间通讯(IPC) 来处理用户的请求,下面咱们就来看看它的运行原理。
FastCGI 进程管理器启动时会建立一个 主(Master) 进程和多个 CGI 解释器进程(Worker 进程),而后等待 Web 服务器的链接。
Web 服务器接收 HTTP 请求后,将 CGI 报文经过 套接字(UNIX 或 TCP Socket)进行通讯,将环境变量和请求数据写入标准输入,转发到 CGI 解释器进程。
CGI 解释器进程完成处理后将标准输出和错误信息从同一链接返回给 Web 服务器。
CGI 解释器进程等待下一个 HTTP 请求的到来。
若是仅仅由于工做模式的不一样,彷佛并无什么大不了的。并没到非要选择 FastCGI 协议不可的地步。
然而,对于这个看似微小的差别,但意义非凡,最终的结果是实现出来的 Web 应用架构上的差别。
在 CGI 协议中,Web 应用的生命周期彻底依赖于 HTTP 请求的声明周期。
对每一个接收到的 HTTP 请求,都须要重启一个 CGI 进程来进行处理,处理完成后必须关闭 CGI 进程,才能达到通知 Web 服务器本次 HTTP 请求处理完成的目的。
可是在 FastCGI 中彻底不同。
FastCGI 进程是常驻型的,一旦启动就能够处理全部的 HTTP 请求,而无需直接退出。
经过前面的讲解,咱们相比已经能够很准确的说出来 FastCGI 是一种通讯协议 这样的结论。如今,咱们就将关注的焦点挪到协议自己,来看看这个协议的定义。
同 HTTP 协议同样,FastCGI 协议也是有消息头和消息体组成。
主要的消息头信息以下:
Version: 用于表示 FastCGI 协议版本号。
Type: 用于标识 FastCGI 消息的类型 - 用于指定处理这个消息的方法。
RequestID: 标识出当前所属的 FastCGI 请求。
Content Length: 数据包包体所占字节数。
BEGIN_REQUEST: 从 Web 服务器发送到 Web 应用,表示开始处理新的请求。
ABORT_REQUEST: 从 Web 服务器发送到 Web 应用,表示停止一个处理中的请求。好比,用户在浏览器发起请求后按下浏览器上的「中止按钮」时,会触发这个消息。
END_REQUEST: 从 Web 应用发送给 Web 服务器,表示该请求处理完成。返回数据包里包含「返回的代码」,它决定请求是否成功处理。
PARAMS: 「流数据包」,从 Web 服务器发送到 Web 应用。此时能够发送多个数据包。发送结束标识为从 Web 服务器发出一个长度为 0 的空包。且 PARAMS 中的数据类型和 CGI 协议一致。即咱们使用 $_SERVER 获取到的系统环境等。
STDIN: 「流数据包」,用于 Web 应用从标准输入中读取出用户提交的 POST 数据。
STDOUT: 「流数据报」,从 Web 应用写入到标准输出中,包含返回给用户的数据。
Web 服务器接收用户请求,但最终处理请求由 Web 应用完成。此时,Web 服务器尝试经过套接字(UNIX 或 TCP 套接字,具体使用哪一个由 Web 服务器配置决定)链接到 FastCGI 进程。
FastCGI 进程查看接收到的链接。选择「接收」或「拒绝」链接。若是是「接收」链接,则从标准输入流中读取数据包。
若是 FastCGI 进程在指定时间内没有成功接收到链接,则该请求失败。不然,Web 服务器发送一个包含惟一的RequestID 的 BEGIN_REQUEST 类型消息给到 FastCGI 进程。后续全部数据包发送都包含这个 RequestID。 而后,Web 服务器发送任意数量的 PARAMS 类型消息到 FastCGI 进程。一旦发送完毕,Web 服务器经过发送一个空PARAMS 消息包,而后关闭这个流。 另外,若是用户发送了 POST 数据 Web 服务器会将其写入到 标准输入(STDIN) 发送给 FastCGI 进程。当全部 POST 数据发送完成,会发送一个空的 标准输入(STDIN) 来关闭这个流。
同时,FastCGI 进程接收到 BEGINREQUEST 类型数据包。它能够经过响应 ENDREQUEST 来拒绝这个请求。或者接收并处理这个请求。若是接收请求,FastCGI 进程会等待接收全部的 PARAMS 和 标准输入数据包。 而后,在处理请求并将返回结果写入 标准输出(STDOUT) 流。处理完成后,发送一个空的数据包到标准输出来关闭这个流,而且会发送一个 END_REQUEST 类型消息通知 Web 服务器,告知它是否发生错误异常。
若是是每一个链接仅处理一个请求,发送 RequestID 则略显多余。
可是咱们的 Web 服务器和 FastCGI 进程之间的链接可能处理多个请求,即一个链接能够处理多个请求。因此才须要采用数据包协议而不是直接使用单个数据流的缘由:以实现「多路复用」。
所以,因为每一个数据包都包含惟一的 RequestID,因此 Web 服务器才能在一个链接上发送任意数量的请求,而且 FastCGI 进程也可以从一个链接上接收到任意数量的请求数据包。
另外咱们还须要明确一点就是 Web 服务器 与 FastCGI 进程间通讯是 无序的。即便咱们在交互过程当中看起来一个请求是有序的,可是咱们的 Web 服务器也有可能在同一时间发出几十个 BEGIN_REQUEST 类型的数据包,以此类推。
PHP-FPM即PHP-FastCGI Process Manager.
PHP-FPM是FastCGI的实现,并提供了进程管理的功能。
进程包含 master 进程和 worker 进程两种进程。
master 进程只有一个,负责监听端口,接收来自 Web Server 的请求,而 worker 进程则通常有多个(具体数量根据实际须要配置),每一个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方。
PHP-FPM 是 FastCGI 进程管理器(PHP FastCGI Process Manager)(http://php.net/manual/zh/install.fpm.php),用于替换 PHP 内核的 FastCGI 的大部分附加功能(或者说一种替代的 PHP FastCGI 实现),对于高负载网站是很是有用的。
PHP-FPM 进程管理器有两种进程组成,一个 Master 进程和多个 Worker 进程。Master 进程负责监听端口,接收来自 Web 服务器的请求,而后指派具体的 Worker 进程处理请求;worker 进程则通常有多个 (依据配置决定进程数),每一个进程内部都嵌入了一个 PHP 解释器,用来执行 PHP 代码。
Nginx 服务器没法直接与 FastCGI 服务器进行通讯,须要启用 ngx_http_fastcgi_module 模块进行代理配置,才能将请求发送给 FastCGI 服务。
转载: