0%

Nginx与PHP的交互机制(1)

Nginx与PHP的交互机制(1)

from there https://www.awaimai.com/371.html

在搭建 LAMP/LNMP 服务器时,会经常遇到 PHP-FPM、FastCGI和CGI 这几个概念。如果对它们一知半解,很难搭建出高性能的服务器。接下来我们就以图形方式,解释这些概念之间的关系。

基础

在整个网站架构中,Web Server(如Apache)只是内容的分发者。举个栗子,如果客户端请求的是 index.html,那么Web Server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。

php-nginx-1

如果请求的是 index.php,根据配置文件,Web Server知道这个不是静态文件,需要去找 PHP 解析器来处理,那么他会把这个请求简单处理,然后交给PHP解析器。

php-nginx-2

当Web Server收到 index.php 这个请求后,会启动对应的 CGI 程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程,Web server再把结果返回给浏览器。这就是一个完整的动态PHP Web访问流程

CGI

CGI是 Web Server 与 Web Application 之间数据交换的一种协议。
CGI全称是“公共网关接口”(Common Gateway Interface),描述的是服务器和请求处理程序之间传输数据的一种标准(服务器与你的或其它机器上的程序进行“交谈”的一种工具)。 所以,CGI是一种协议。CGI可用于任何语言,只要该语言具有标准的输出、输入以及环境变量。如perl、php等语言。 以nginx和php为例,我们可以理解为,这是php在与nginx服务器之间交互时,对传输数据的一种约定。

CGI的原理是什么?
当需要请求使用网关的资源时,服务器会请辅助应用程序来处理请求(比如nginx会请php程序来处理请求)。 服务器会将辅助应用程序的数据传送给网关。然后网关会向服务器返回一条响应或者响应数据,服务器再将响应或响应数据转发给客户端。
cgi

由此我们可以清楚两点:

  1. 服务器和网关是相互独立的应用程序
  2. 服务器是应用程序和网关之间的一座桥梁

由此,我们可知CGI有一个致命的弱点,即应用程序的每次请求,都要引发一个全新的进程。所以,服务器和网关之间的分离会造成性能的 耗费,会限制使用CGI的服务器的性能,并且会加重服务端机器资源的负担。
好啦,重角要登场了。后来为了解决这个问题,出现了FastCGI,也就是快速的CGI。 接下来,我们再详细的了解下FastCGI

FastCGI

FastCGI:(Fast Common Gateway Interface),即快速通用网关接口,是一种让交互程序与Web服务器通信的协议。它是CGI的增强版本 FastCGI致力于减少网页服务器与CGI程序之间互动的开销,从而使服务器可以同时处理更多的网页请求。
以上来自维基百科,我们可以由此了解到,FastCGICGI一样,也是一种协议,只不过它是CGI的增强版本。
FastCGI是如何增强性能的呢? FastCGI接口模拟了CGI,但FastCGI是作为持久守护进程运行的,消除了为每个请求建立或拆除新进程所带来的性能损耗。也就是允许,一个进程内可以处理多个请求。 也就说CGI解释器保持在内存中,并接受了FastCGI进程管理和调度,所以它可以提供更好的性能,可扩展性,故障切换等特点

FastCGI的特点:

  1. FastCGI与语言无关
  2. FastCGI应用在进程中,独立于核心网络服务器,提供了一个比API环境更安全的环境。 APIs的代码和web服务器的应用的核心是 紧紧关联的。这也就意味着在API应用程序的错误可能会损坏其它应用程序或核心服务器。恶意API应用程序代码甚至可以窃取另一个应用程序或核心服务器密钥。
  3. FastCGI技术目前支持PHP,C/C++, Java lanuage, Perl, Tcl, Python, SmallTalk, Ruby etc.. 它在Apache, ISS, Lighttpd和其他流行的 服务器中的相关模块都是可以使用的。FastCGI不依赖于任何服务器体系结构,所以即使服务器在技术上改变了,FastCGI还是稳定的

FastCGI的工作原理

  1. Web Server 启动时载入FastCGI进程管理器 (IIS ISAPI 或Apache Module)
  2. FastCGI进程管理器首先初始化自己,启动一批CGI解释器进程(可见多个php-cgi),然后等待来自Web Server的连接。
  3. 当Web Server中的一个客户端请求达到时, FastCGI进程管理器会选择并连接一个CGI解释器。Web server的CGI环境变量和标准输入会被送达FastCGI进程的php-cgi。
  4. FastCGI子进程从同一连接完成返还给Web Server的标准输出和错误信息。当请求进程完成后,FastCGI进程会关闭此连接。FastCGI会等待并出来来自FastCGI进程管理器(运行在Web Server中的)的下一个连接。 在CGI模式,php-cgi然后会退出。

nginx-fastcgi-php

如上图所示,FastCGI的下游,是CGI-APP,在我们的LNMP架构里,这个CGI-APP就是PHP程序。
而FastCGI的上游是Nginx,他们之间有一个通信载体,即图中的socket。
上图中的Pre-fork,则对应着我们PHP-FPM的启动,也就是在我们启动PHP-FPM时便会根据用户配置启动诸多FastCGI触发器(FastCGI Wrapper)。

FastCGI的不足 因为是多进程,所以比CGI多线程消耗更多的服务器内存,PHP-CGI解释器每进程消耗7至25兆内存,将这个数字乘以50或100就是很大的内存数。 Nginx 0.8.46+PHP 5.2.14(FastCGI)服务器在3万并发连接下,开启的10个Nginx进程消耗150M内存(15M_10=150M),开启的64个php-cgi进程消耗1280M内存(20M_64=1280M),加上系统自身消耗的内存,总共消耗不到2GB内存。 如果服务器内存较小,完全可以只开启25个php-cgi进程,这样php-cgi消耗的总内存数才500M。 上面的数据摘自Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过Apache十倍的Web服务器(第6版)

PHP-CGI

PHP-CGI:是 PHP (Web Application)对 Web Server 提供的 CGI 协议的接口程序,是PHP自带的FastCGI管理器。

PHP-CGI的不足:

  1. php-cgi变更php.ini配置后需重启php-cgi才能让新的php-ini生效,不可以平滑重启
  2. 直接杀死php-cgi进程,php就不能运行了。(PHP-FPM和Spawn-FCGI就没有这个问题,守护进程会平滑从新生成新的子进程。)

PHP-FPM

PHP-FPM:是 PHP(Web Application)对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相对智能一些任务管理。
PHP-FPM的全称是PHP FastCGI Process Manager。
它是 PHP 针对 FastCGI 协议的具体实现,它会通过用户配置来管理一批FastCGI进程.
因此它也是PHP 在多种服务器端应用编程端口(SAPI:cgi、fast-cgi、cli、isapi、apache)里使用最普遍、性能最佳的一款进程管理器。
在PHP-FPM管理下的某个FastCGI进程挂了,PHP-FPM会根据用户配置来看是否要重启补全。
PHP-FPM更像是管理器,负责管理PHP FastCGI,而真正衔接Nginx与PHP的则是FastCGI进程。
因此,CGI是通用网关协议,FastCGI则是一种常驻进程的CGI模式程序,而PHP-FPM更像是管理器,用于管理FastCGI进程。
WEB 中:

  • Web Server 一般指Apache、Nginx、IIS、Lighttpd、Tomcat等服务器,
  • Web Application 一般指PHP、Java、Asp.net等应用程序。

Nginx+PHP的工程模式下,两位主角分工明确,Nginx负责承载HTTP请求的响应与返回,以及超时控制记录日志等HTTP相关的功能,而PHP则负责处理具体请求要做的业务逻辑,它们俩的这种合作模式也是常见的分层架构设计中的一种,在它们各有专注面的同时,FastCGI又很好的将两块衔接,保障上下游通信交互,这种通过某种协议或规范来衔接好上下游的模式,在我们日常的PHP应用开发中也有这样的思想落地,譬如我们所开发的高性能API,具体的Client到底是PC、APP还是某个其他程序,我们不关心,而这些PC、APP、第三方程序也不关心我们的PHP代码实现,他们按照API的规范来请求做处理即可