PHP 运行模式介绍

老牛浏览 418评论 0发表于

1. 简介

PHP 常见的运行模式有 4 种:

  1. CGI

  2. FastCGI

  3. CLI

  4. 模块

2. CGI

CGI 即通用网关接口(Common Gateway Interface),它是一种协议。

首先,CGI 是干嘛的?CGI 是为了保证 Web Server 传递过来的数据是标准格式的,方便 CGI 程序的编写者。

Web Server(比如 Nginx)只是内容的分发者。比如,如果请求 /index.html,那么 Web Server 会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。好了,如果现在请求的是 /index.php,根据配置文件,Nginx 知道这个不是静态文件,需要去找 PHP 解析器来处理,那么他会把这个请求简单处理后交给 PHP 解析器。Nginx 会传哪些数据给 PHP 解析器呢?URL 要有吧,查询 query 也得有吧,POST 数据也要有,HTTP header 也不能少吧,好的,CGI 就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在 PHP 代码中使用的用户从哪里来的。

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

每有一个用户请求,都要先创建 CGI 的子进程,然后处理请求,处理完成后结束子进程,这就是 Fork-And-Execute 模式。当用户请求数量非常多时,会大量占用系统资源。所以用 CGI 方式的服务器,有多少连接请求就会有多少 CGI 子进程,子进程反复加载是 CGI 性能低下的主要原因。

3. FastCGI

CGI 程序的性能问题在哪?「PHP解析器会解析 php.ini 文件,初始化执行环境」,就是这里了。标准的 CGI 对每个请求都会执行这些步骤,所以处理每个请求的时间会较长。FastCGI 是 CGI 的升级版本,FastCGI 像是一个常驻(long-live)型的 CGI。

Web Server启动时,载入 FasterCGI 进程管理器 master。FastCGI 进程管理器自身初始化,启动多个 CGI 解释器进程 worker(可见多个 php-cgi.exe 或 php-cgi),并等待来自 Web Server 的连接。当请求过来时,master 会将其交付给 worker,worker 处理完将结果返回给 Web Server,等待处理下一个连接。而在正常的 CGI 模式中,php-cgi 在此就退出了。你可以想象 CGI 通常有多慢,每一个请求 PHP 都必须重新解析 php.ini、重新载入 dll 扩展并重新初始化全部数据。使用 FastCGI,所有这些只在 master 进程启动时发生一次。这样就避免了重复的初始化,效率自然提高了。而且,当 worker 不够用时,master 可以根据配置项预先启动几个 worker 等着;当空闲的 worker 太多时,也会停掉一些,这样就提高了性能,也节约了资源。一个额外的好处是,持续数据库连接可以工作。

对比CGI的优点:

  • 从稳定性上看,FastCGI 是以独立的进程池来运行 CGI,单独一个进程死掉,系统可以很轻易的丢弃,然后重新分配新的进程来运行。

  • 从安全性上看,FastCGI 支持分布式运算。FastCGI 和宿主的 Server 完全独立,FastCGI 挂了不会把 Server 也搞挂了。

  • 从性能上看,FastCGI 把动态逻辑的处理从 Server 中分离出来,大负荷的 IO 处理还是留给宿主 Server,这样 Server 可以一心一意做 IO。

4. PHP-FPM

那么 PHP-FPM 又是什么呢?是一个实现了 FastCGI 的程序,PHP 5.3.3 开始已经被集成到 PHP 中了。

大家都知道,PHP 的解释器是 php-cgi。php-cgi 只是个 CGI 程序,本身只能解析请求,返回处理结果,不会进程管理。所以就出现了一些能够调度 php-cgi 进程的程序,比如 spawn-fcgi,当然还有 PHP-FPM。简单来说,FastCGI 是一个协议,PHP-FPM 实现了这个协议。

5. CLI

PHP-CLI 即 PHP Command Line Interface。PHP 不仅可以作为服务端脚本,还可以以命令行脚本方式运行,结合 Shell 脚本,能够实现丰富的功能。比如在 Linux 系统中结合 Crontab 来实现计划任务,备份数据库,每天定时重置排行榜数据等。

6. 模块

模块模式是以 mod_php5 模块的形式集成,此时 mod_php5 模块的作用就是接受 Apache 传递过来的 PHP 文件请求,处理后将结果返回给 Apache。

如果我们在 Apache 启动前在其配置文件中配置好了 PHP 模块(mod_php5),PHP 模块通过注册 apache2 的 ap_hook_post_config 挂钩,在 Apache 启动的时候启动此模块以接受 PHP 文件的请求。

除了这种启动时的加载方式,Apache 的模块可以在运行的时候动态装载,这意味着对服务器可以进行功能扩展而不需要重新对源代码进行编译,甚至根本不需要停止服务器。我们所需要做的仅仅是给服务器发送信号 HUP 或者 AP_SIG_GRACEFUL 通知服务器重新载入模块。但是在动态加载之前,我们需要将模块编译成为动态链接库。此时的动态加载就是加载动态链接库。Apache 中对动态链接库的处理是通过模块 mod_so 来完成的,因此 mod_so 模块不能被动态加载,它只能被静态编译进 Apache 的核心。这意味着它是随着 Apache 一起启动的。

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

ini
LoadModule php5_module modules/mod_php5.so

这里我们使用了 LoadModule 命令,该命令的第一个参数是模块的名称,名称可以在模块实现的源码中找到。第二个选项是该模块所处的路径。如果需要在服务器运行时加载模块,可以通过发送信号 HUP 或者 AP_SIG_GRACEFUL 给服务器,一旦接受到该信号,Apache 将重新装载模块,而不需要重新启动服务器。该运行模式是我们以前在 Windows 环境下使用 Apache 服务器经常使用的,而在模块化(DLL)中,PHP 是与 Web 服务器一起启动并运行的。(它是 Apache 在 CGI 的基础上进行的一种扩展,加快 PHP 的运行效率)。

点赞
收藏
暂无评论,快来发表评论吧~
私信
老牛@ilaoniu
老牛,俗称哞哞。单纯的九零后理工小青年。喜欢折腾,爱玩,爱音乐,爱游戏,爱电影,爱旅游...
最后活跃于