介绍

在用PHP开发的过程中,我们常常使用Nginx或者Apache作为我们的Web服务器。但是PHP是如何与这些Web服务器通信的呢?

  • Apache把PHP作为一个模块集成到Apache进程(httpd)运行,这种mod_php的运行模式与PHP-CGI没有任何关系。

  • Nginx是通过FastCGI来实现与PHP的通信。

要谈FastCGI就必须先说说CGI。那什么是CGI?

CGI(Common Gateway Interface:通用网关接口)是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能。CGI 应用程序能与浏览器进行交互,还可通过数据库API 与数据库服务器等外部数据源进行通信,从数据库服务器中获取数据。--百度百科

CGI协议同 HTTP 协议一样是一个「应用层」协议,它的 功能 是为了解决 Web 服务器与 PHP 应用(或其他 Web 应用)之间的通信问题。

既然它是一个「协议」,换言之它与语言无关,即只要是实现类 CGI 协议的应用就能够实现相互的通信。

深入CGI协议

我们已经知道了 CGI 协议是为了完成 Web 服务器和应用之间进行数据通信这个问题。那么,这一节我们就来看看究竟它们之间是如何进行通信的。

简单来讲 CGI 协议它描述了 Web 服务器和应用程序之间进行数据传输的格式,并且只要我们的编程语言支持标准输入(STDIN)、标准输出(STDOUT)以及环境变量等处理,你就可以使用它来编写一个 CGI 程序。

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 进程,处理完成后立即关闭。

CGI协议的缺陷

  • 每次处理用户请求,都需要重新 fork CGI 子进程、销毁 CGI 子进程。

  • 一系列的 I/O 开销降低了网络的吞吐量,造成了资源的浪费,在大并发时会产生严重的性能问题。

深入FastCGI协议

从功能上来讲,CGI 协议已经完全能够解决 Web 服务器与 Web 应用之间的数据通信问题。但是由于每个请求都需要重新 fork 出 CGI 子进程导致性能堪忧,所以基于 CGI 协议的基础上做了改进便有了 FastCGI 协议,它是一种常驻型的 CGI 协议。

本质上来将 FastCGI 和 CGI 协议几乎完全一样,它们都可以从 Web 服务器里接收到相同的数据,不同之处在于采取了不同的通信方式。

再来回顾一下 CGI 协议每次接收到 HTTP 请求时,都需要经历 fork 出 CGI 子进程、执行处理并销毁 CGI 子进程这一系列工作。

FastCGI 协议采用 进程间通信(IPC) 来处理用户的请求,下面我们就来看看它的运行原理。

FastCGI协议运行原理

  • FastCGI 进程管理器启动时会创建一个 主(Master) 进程和多个 CGI 解释器进程(Worker 进程),然后等待 Web 服务器的连接。

  • Web 服务器接收 HTTP 请求后,将 CGI 报文通过 套接字(UNIX 或 TCP Socket)进行通信,将环境变量和请求数据写入标准输入,转发到 CGI 解释器进程。

  • CGI 解释器进程完成处理后将标准输出和错误信息从同一连接返回给 Web 服务器。

  • CGI 解释器进程等待下一个 HTTP 请求的到来。

为什么是 FastCGI 而非 CGI 协议

如果仅仅因为工作模式的不同,似乎并没有什么大不了的。并没到非要选择 FastCGI 协议不可的地步。

然而,对于这个看似微小的差异,但意义非凡,最终的结果是实现出来的 Web 应用架构上的差异。

CGI 与 FastCGI 架构

在 CGI 协议中,Web 应用的生命周期完全依赖于 HTTP 请求的声明周期。

对每个接收到的 HTTP 请求,都需要重启一个 CGI 进程来进行处理,处理完成后必须关闭 CGI 进程,才能达到通知 Web 服务器本次 HTTP 请求处理完成的目的。

但是在 FastCGI 中完全不一样。

FastCGI 进程是常驻型的,一旦启动就可以处理所有的 HTTP 请求,而无需直接退出。

再看 FastCGI 协议

通过前面的讲解,我们相比已经可以很准确的说出来 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 服务器和 FastCGI 交互过程

  • 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 这个标识?

如果是每个连接仅处理一个请求,发送 RequestID 则略显多余。

但是我们的 Web 服务器和 FastCGI 进程之间的连接可能处理多个请求,即一个连接可以处理多个请求。所以才需要采用数据包协议而不是直接使用单个数据流的原因:以实现「多路复用」。

因此,由于每个数据包都包含唯一的 RequestID,所以 Web 服务器才能在一个连接上发送任意数量的请求,并且 FastCGI 进程也能够从一个连接上接收到任意数量的请求数据包。

另外我们还需要明确一点就是 Web 服务器 与 FastCGI 进程间通信是 无序的。即使我们在交互过程中看起来一个请求是有序的,但是我们的 Web 服务器也有可能在同一时间发出几十个 BEGIN_REQUEST 类型的数据包,以此类推。

PHP-FPM

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如何工作的?

PHP-FPM 进程管理器有两种进程组成,一个 Master 进程和多个 Worker 进程。Master 进程负责监听端口,接收来自 Web 服务器的请求,然后指派具体的 Worker 进程处理请求;worker 进程则一般有多个 (依据配置决定进程数),每个进程内部都嵌入了一个 PHP 解释器,用来执行 PHP 代码。

Nginx 服务器如何与 FastCGI 协同工作

Nginx 服务器无法直接与 FastCGI 服务器进行通信,需要启用 ngx_http_fastcgi_module 模块进行代理配置,才能将请求发送给 FastCGI 服务。

转载:

PHP和Apache是如何通信的?

Nginx+PHP-FPM运行原理详解

掌握CGI和FastCGI协议的运行原理

CGI 和 FastCGI 协议的运行原理的更多相关文章

  1. 【转】CGI 和 FastCGI 协议的运行原理

    介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 Fa ...

  2. php之CGI、FastCGI、php-fpm运行原理

    学好一门语言,必须懂得他得运行原理,php之CGI.FastCGI.php-fpm运行原理 早期的webserver只处理html等静态文件,但是随着技术的发展,出现了像php等动态语言.webser ...

  3. 简单了解下CGI、FastCGI和php-fpm的概念和区别和运行原理

    什么是CGI? CGI(Common Gateway Interface),公共网关接口,它是Web服务器与外部应用程序(CGI程序)之间传递信息的接口标准.通过CGI接口,Web服务器就能够获取客户 ...

  4. nginx如何调用PHP(nginx+php运行原理)

    采用nginx+php作为webserver的架构模式,在现如今运用相当广泛.然而第一步需要实现的是如何让nginx正确的调用php.由于nginx调用php并不是如同调用一个静态文件那么直接简单,是 ...

  5. Nginx+Php-fpm运行原理详解

    一.代理与反向代理 现实生活中的例子 1.正向代理:访问google.com 如上图,因为google被墙,我们需要vpnFQ才能访问google.com. vpn对于“我们”来说,是可以感知到的(我 ...

  6. Nginx+Php-fpm运行原理

    一.代理与反向代理 现实生活中的例子 1.正向代理:访问google.com 如上图,因为google被墙,我们需要vpnFQ才能访问google.com. vpn对于“我们”来说,是可以感知到的(我 ...

  7. Nginx+Php-fpm运行原理 代理与反向代理

    一.代理与反向代理 现实生活中的例子 1.正向代理:访问google.com 如上图,因为google被墙,我们需要vpnFQ才能访问google.com.Virtual Private Networ ...

  8. php-fpm,cgi,fast-cgi,nginx,php.ini,php-fpm.conf,nginx.conf

    php-fpm.conf 是PHP-FPM特有的配置文件. php.ini 是所以php模式中必须的配置文件. 两者的区别是,php-fpm.conf 是PHP-FPM进程管理器的配置文件,php.i ...

  9. (转)Nginx+Php-fpm运行原理详解

    一.代理与反向代理 现实生活中的例子 1.正向代理:访问google.com 如上图,因为google被墙,我们需要vpn翻墙才能访问google.com. vpn对于“我们”来说,是可以感知到的(我 ...

随机推荐

  1. Zabbix Agent 源码编译安装

    简介: 单独整理一下 Zabbix Agent . 1.安装包选择 下载地址:http://www.zabbix.com/download.php 这里有两种源码包,一种是安装 Zabbix Serv ...

  2. 图片的滑动缩放html、css、js代码

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  3. SQL Server日志文件过大 大日志文件清理方法 不分离数据库

    SQL Server日志文件过大    大日志文件清理方法 ,网上提供了很多分离数据库——〉删除日志文件-〉附加数据库 的方法,此方法风险太大,过程也比较久,有时候也会出现分离不成功的现象.下面的方式 ...

  4. as3.0 嵌入字体的用法

    var txt:TextField = new TextField();//创建文本 txt.embedFonts=true;//确定嵌入字体 var font:Font=new MyFont();/ ...

  5. java正则积累

    1. [.]点:再分割的时候不可以直接使用点,需要加上 \\ 转义才可以得到想要的结果,否则输出的时候会报异常 数据下标越界 String[] split = "output.txt&quo ...

  6. C++ 获取字符串中的所有汉字

    #include<iostream> using namespace std; int main() {    char str[20] = "cd大家好df";   ...

  7. 【mac上安装&配置&使用git】

    转自:https://www.jianshu.com/p/7edb6b838a2e 目录 安装git 创建ssh key.配置git 提交本地项目到GitHub 一.安装Git MAC 上安装Git主 ...

  8. Quartz.Net进阶之四:CronTrigger 详述

    以前都是将所有的内容放在一篇文章里,就会导致文章很长,对于学习的人来说,有时候这也是一个障碍.所以,以后我的写作习惯,我就会把我写的文章缩短,但是内容不会少,内容更集中.这样,学习起来也不会很累,很容 ...

  9. Python3实战系列之九(获取印度售后数据项目)

    项目现状:已经部署在服务器上并正常运行了. 1.服务器上的部署 2.下载到服务器的文件列表 3.转存在到数据库SQL Server中的数据 项目总结:这次项目采用python来实现,刚开始还是有点担忧 ...

  10. Eclipse中代码自动提示功能设置

    Eclipse中代码自动提示功能设置 1 打开eclipse→Windows→Preferences→Java→Editor→Content Assist: 修改Auto Activation tri ...