您当前的位置:首页 > 计算机 > 精彩资源

CGI、FastCGI、PHP-FPM与Module模式

时间:04-02来源:作者:点击数:

CGI

最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态HTML。随着对网站的需求日益复杂,一些语言开始能写出动态网站,但是服务器本身并不能直接解析这些文件,服务器自己不能做,只能交给第三方处理,但是要提前与第三方做好约定,我给你什么,然后你给我什么,就是我把请求参数发送给你,然后我接收你的处理结果,再返回给客户端。那这个约定就是 Common Gateway Interface,简称CGI。这个协议可以用PHP、Python、C/C++来实现。如PHP-CGI,就是对CGI协议的实现。

这里写图片描述

服务器与CGI程序的交互步骤:

WEB服务器将根据CGI程序的类型决定数据向CGI程序的传送方式,一般来讲是通过标准输入/标准输出流环境变量来与CGI程序间进行数据的传递。 如下图所示:

这里写图片描述

CGI程序通过标准输入(STDIN)标准输出(STDOUT)来进行输入输出数据。此外 CGI程序还通过环境变量来得到输入,操作系统提供了许多环境变量,它们定义了程序的执行环境,应用程序可以读取它们。Web服务器和CGI接口又另外设置了一些环境变量,用来向CGI程序传递一些重要的参数。

一些常用的CGI环境变量如:CONTENT_TYPE、CONTENT_LENGTH、HTTP_COOKIE、QUERY_STRING、REMOTE_HOST等,在PHP脚本中,都可以通过 $_SERVER[‘xxx’]来获取。这些CGI环境变量都是服务器程序通过 setenv() 设置的。

简单总结,整个服务器接收请求到响应请求有如下几步:

1、通过Internet把用户请求送到服务器。 
2、服务器接收用户请求并转交给CGI程序处理,同时传递一些变量。
3、CGI程序把处理结果传送给服务器。 
4、服务器把结果送回到用户。
这里写图片描述

CGI方式在遇到连接请求(用户请求)先要创建CGI的子进程,然后该进程请求,处理完后结束这个子进程。这就是令人诟病的fork-and-execute模式。

所以用CGI方式的服务器有多少连接请求就会有多少CGI进程,进程反复加载初始化,每次都要做些大量重复的操作是CGI性能低下的主要原因。都会当用户请求数量非常多时,会大量挤占系统的资源如内存,CPU时间等,造成性能低下。

比如CGI模式下运行的PHP,每次启动CGI进程启动都要初始化 Zend引擎和核心组件、重新载入全部扩展、解析php.ini等等一系列的操作,这就造成了资源的严重浪费。

FastCGI

为了解决CGI性能低下的问题,FastCGI就出现了。

FastCGI像是一个常驻(long-live)型的CGI,实现了FastCGI协议的程序,作为一个CGI的管理服务器存在,会预先启动一系列的子进程来等待处理,然后等待 web服务器发过来的请求,一旦接受到请求就交由子进程处理,由于不需要等接受到请求后再启动CGI,会快很多。

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

FastCGI特点

  • FastCGI具有语言无关性.
  • FastCGI在进程中的应用程序,独立于核心web服务器运行,提供了一个比API更安全的环境。APIs把应用程序的代码与核心的web服务器链接在一起,这意味着在一个错误的API的应用程序可能会损坏其他应用程序或核心服务器。 恶意的API的应用程序代码甚至可以窃取另一个应用程序或核心服务器的密钥。
  • FastCGI技术目前支持语言有:PHP、C/C++、Java、Perl、Tcl、Python、SmallTalk、Ruby等。相关模块在Apache, ISS, Lighttpd等流行的服务器上也是可用的。
  • FastCGI本身不依赖于任何Web服务器的内部架构,因此即使服务器技术的变化, FastCGI依然稳定不变。

FastCGI的工作流程

这里写图片描述
1、FastCGI进程管理器自身初始化,启动多个CGI程序(可见多个php-cgi)并等待来自Web Server的连接。
2、Web服务器与FastCGI进程管理器进行Socket通信,通过 FastCGI协议发送CGI环境变量和标准输入给CGI程序。
3、CGI程序完成处理后将标准输出从同一TCP连接返回 Web 服务器。
4、CGI程序接着等待并处理来自Web服务器的下一个请求。

FastCGI与传统CGI模式的区别之一则是Web服务器不是直接执行 CGI程序了,而是通过Socket与FastCGI 进程管理器进行交互,也正是因为FastCGI进程管理器是基于Socket通信的,所以也是分布式的,Web 服务器可以和响应器服务器分开部署。Web服务器需要将数据 CGI/1.1 的规范封装在遵循 FastCGI 协议包中发送给 FastCGI进程管理器。

使用FastCGI,许多繁杂的工作都只在php-cgi进程启动时发生一次。一个额外的好处是,持续数据库连接可以工作,并且同一个进程中的请求都可以使用这个连接。

PHP-FPM

PHP-FPM是PHP对FastCGI 的一种具体实现,它的启动后自行读取php.ini和php-fpm.conf,并创建多个 CGI子进程,然后主进程负责管理子进程,同时它对外提供一个SOCKET, Web服务器要转发一个请求时只需要按照FastCGI协议要求的格式将数据发往这个SOCKET就行了,PHP-FPM创建的这些子进程会去争抢这个 SOCKET连接,谁抢到了谁就处理该请求并将结果返回给Web服务器。

它作为一个独立的进程存在,通过SOCKET与Nginx建立连接。它和Apache + module_php有相像之处。

PHP-FPM采用多进程模式来实现并发:

这里写图片描述

每个进程里串行地执行每个请求(使用poll处理请求):

这里写图片描述

一个master进程,支持多个pool,每个pool由master进程监听不同的端口,pool中有多个worker进程。

每个worker进程支持在运行时编译脚本并在内存中缓存生成的 Opcode来提升性能。

可以通过pm.max_requests配置来指定,每个worker进程响应多少请求后自动重启。(重启是为了解决偶尔发生的内存泄露问题)

每个worker进程支持保持一个到MySQL/Memcached/Redis的持久连接,实现”连接池”,避免一个进程中的多个请求重复地建立连接,对程序透明。

master进程并不接收和分发请求,而是worker进程直接accpet请求后poll处理。

如果worker进程不够用,master进程会prefork更多进程。

如果prefork达到了pm.max_children上限,worker进程又全都繁忙,这时master进程会把请求挂起到连接队列backlog里(默认值是511)。

在PHP-FPM中,PHP的所有变量都在请求时创建,请求结束后全部销毁,也就是每个请求之间都是独立的,这虽然避免了内存泄露,但是对于某些大数组、对象、常量,重复地创建非常浪费资源(即使使用了 APC/OpCache,也只是节省了编译Opcode的时间,但是Opcode依然要执行并且花费时间)。若想实现将这些常驻内存,可以考虑使用Swoole扩展来作Server,替代Nginx+PHP-FPM。

模块模式

Module模式下,Apache以mod_phpX模块的形式集成PHP,此时mod_phpX模块的作用是接收Apache传递过来的PHP文件请求,并处理这些请求,然后将处理后的结果返回给Apache。如果我们在Apache启动前在其配置文件中配置好了PHP模块(mod_phpX), PHP模块通过注册apache2的ap_hook_post_config挂钩,在Apache启动的时候加载此模块(-l),以此模块来处理PHP文件的HTTP请求。

除了这种启动时的加载方式,Apache的模块可以在运行时加载动态库(dlopen()),这意味着对服务器可以进行功能扩展而不需要重新对源代码进行编译,甚至根本不需要停止服务器。我们所需要做的仅仅是给服务器发送信号HUP或者AP_SIG_GRACEFUL通知服务器重新载入模块。但是在动态加载之前,我们需要将模块编译成为动态链接库。此时的动态加载就是加载动态链接库。

Apache中对动态链接库的处理都是通过模块mod_so来完成的,因此mod_so模块不能使用动态加载(dlopen)的,它只能被静态编译进Apache。这意味着它是随着Apache一起启动的。

Apache是如何加载模块的呢?我们以前面提到的mod_php5模块为例。首先我们需要在Apache的配置文件httpd.conf中添加一行:

LoadModule phpX_module modules/mod_phpX.so

这里我们使用了LoadModule命令,该命令的第一个参数是模块的名称,名称可以在模块实现的源码中找到。第二个选项是该模块所处的路径。如果需要在服务器运行时加载模块,可以通过发送信号HUP或者AP_SIG_GRACEFUL给服务器,一旦接受到该信号,Apache将通过重新装载模块(dlopen()),而不需要重新启动服务器。

该运行模式是我们以前在windows环境下使用apache服务器经常使用的,而在模块化(DLL)中,PHP是与Web服务器一起启动并运行的(可以看成是apache在CGI的基础上进行的一种扩展,加快PHP的运行效率) 。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门