PHP工作原理及五大运行模式:包括cgi 、fast-cgi、cli、isapi、Web模块模式
PHP的五大运行模式
1)CGI( Common Gateway Interface):即通用网关接口,
2)FastCGI( Long-Live CGI):即常驻型通用网关接口
3)CLI( Command Line Interface):即命令行运行接口
4)Web模块模式(Apache等Web服务器运行的模式)
5)ISAPI(Internet Server Application Program Interface)
1.1 CGI是一种让客户端(web浏览器)与Web服务器(nginx等)程序进行通信(数据传输)的协议。
1)用来规范web服务器传输到php解释器中的数据类型以及数据格式,包括URL、查询字符串、POST数据、HTTP header等,也就是为了保证web server传递过来的数据是标准格式的。
2)CGI可以用任何一种具有标准输入、输出和环境变量的语言编写,如php、perl、tcl等。不同类型语言写的程序只要符合cgi标准,就能作为一个cgi程序与web服务器交互,早期的cgi大多都是c或c++编写的。
3)一般说的CGI指的是用各种语言编写的能实现该功能的程序。
1.2.CGI程序的工作原理
1)每次当web server收到index.php这种类型的动态请求后,会启动对应的CGI程序(PHP的解析器);
2)PHP解析器会解析php.ini配置文件,初始化运行环境,然后处理请求,处理完成后将数据按照CGI规定的格式返回给web server然后退出进程;
3)最后web server再把结果返回给浏览器。
1.3 fpm进程管理器是什么?
进程管理器,顾名思义就是管理进程的一个“进程”;
什么意思呢?当我们接到一个请求时,webserver需要和php进行通信;
通信时会成一个主进程,我们把它理解为一个工厂,主进程下会生成子进程去做具体的运算,我们把它理解为工人;
也就是说,工厂的作用是调度,是给工人提供工作的一个平台,工人的作用是去做工作。
1.4 CGI程序的特点
1)高并发时的性能较差:
CGI程序的每一次web请求都会有启动和退出过程,也就是最为人诟病的fork-and-execute模式(每次HTTP服务器遇到动态请求时都需要重新启动脚本解析器来解析php.ini,重新载入全部DLL扩展并重初始化全部数据结构,然后把结果返回给HTTP服务器),很明显,这样的接口方式会导致php的性能很差,在处理高并发访问时,几乎是不可用的。
2)传统的CGI接口方式安全性较差
3)CGI对php.ini的配置很敏感,在开发和调试的时候相当方便
CGI已经是比较老的模式了,这几年都很少用了。 CGI为每一次请求增加一个进程,效率很低,所以基本已经不在生产部署时采用。但由于CGI对php配置的敏感性,通常被用在开发和调试阶段。
通过CGI程序的工作原理可以看出:CGI程序性能较差,安全性较低,为了解决这些问题产生了FastCGI。
php为例,我将一次动态请求相关的概念大致都简单解释一遍。
cgi
:它是一种协议。通过cgi协议,web server可以将动态请求和相关参数发送给专门处理动态内容的应用程序。fastcgi
:也是一种协议,只不过是cgi的优化版。cgi的性能较烂,fastcgi则在其基础上进行了改进。php-cgi
:fastcgi是一种协议,而php-cgi实现了这种协议。不过这种实现比较烂。它是单进程的,一个进程处理一个请求,处理结束后进程就销毁。php-fmp
:是对php-cgi的改进版,它直接管理多个php-cgi进程/线程。也就是说,php-fpm是php-cgi的进程管理器因此它也算是fastcgi协议的实现。在一定程度上讲,php-fpm与php的关系,和tomcat对java的关系是类似的。cgi进程/线程
:在php上,就是php-cgi进程/线程。专门用于接收web server的动态请求,调用并初始化zend虚拟机。cgi脚本
:被执行的php源代码文件。zend虚拟机
:对php文件做词法分析、语法分析、编译成opcode,并执行。最后关闭zend虚拟机。cgi进程/线程和zend虚拟机的关系
:cgi进程调用并初始化zend虚拟机的各种环境。
以php-fpm为例,web server从转发动态请求到结束的过程大致如下:
而每个php-cgi进程的作用大致包括:(有些功能分类错误,请无视,知道大致功能就够了)
注意,尽管php-fpm的全称为PHP FastCGI Process Manager,但严格地讲,php-fpm不是fastcgi的进程管理器,而是php fastcgi即php-cgi的进程管理器。fastcgi只是一种协议,不是进程。就像http协议一样,apache对它的实现是httpd,nginx对它的实现就叫nginx。
再次说明,cgi和fastcgi是一种协议。各种支持和WEB交互的编程语言对cgi/fastcgi协议都做了各自的实现(当然,任何一种语言都能写cgi脚本),而php上的php-cgi和php-fpm正是php对fastcgi协议的实现。
使用CGI模式时
使用CGI模式时,当动态请求到达,httpd临时启动一个cgi解释器,并通过cgi协议转发要运行的内容。当cgi脚本运行结束后,将结果返回给httpd,然后cgi解释器进程自我销毁。当多个动态请求到达时,将先后启动多个cgi解释器。因此,这种方法效率极低。
在注释掉php5_module的LoadModule相关行后,使用action指令指定要使用cgi运行的类型。但注意,action指令是mod_action提供的,所以必须已经加载该模块。
例如:指定MIME类型为image/gif的请求使用images.cgi运行。显然,images.cgi脚本你必须先写好。
Action image/gif /cgi-bin/images.cgi
还可以通过添加handler来复合文件类型,再使用某个cgi脚本去运行这个handler中的任意类型。
AddHandler my-file-type .xyz Action my-file-type "/cgi-bin/program.cgi"
对于php来说,则可以使用安装php时bin目录下提供的php-cgi程序作为cgi程序。
[root@xuexi php]# ls /usr/local/php/bin/ pear peardev pecl phar phar.phar php php-cgi php-config phpize # 复制到apache默认的cgi-bin目录下,方便管理 [root@xuexi php]# cp /usr/local/php/bin/php-cgi /usr/local/apache/cgi-bin/ # 在httpd.conf中添加以下行 Action application/x-httpd-php /usr/local/php/bin/cgi-bin/php-cgi
使用模块方式时
在编译php时,将php5_module模块编译到apache中,例如在编译php时在./configure配置中加上"--with-apxs2=/usr/local/apache/bin/apxs"。
这种交互模式下,httpd在启动时加载并激活php_module。也就是说,php-cgi常驻在httpd进程内部。当动态请求到达时,httpd不用再生成cgi解释器,而是直接将动态请求转发给它内部php-cgi。
配置实用这种交互模式非常简单,只需使用LoadModule加载php_module,再添加对应的MIME处理器即可。
LoadModule php5_module modules/libphp5.so # 在mime模块中添加对应的类型 <IfModule mime_module> AddType application/x-httpd-php .php AddType applicaiton/x-httpd-php-source .phps </IfModule>
使用php-fpm方式时
前面说了,php-fpm是php-cgi的进程管理器。这种交互方式实际上是让php-cgi以独立于httpd的方式存在,目前基本使用php-fpm的方式管理php-cgi进程。也就是说,这种模式下,php-cgi和httpd已经分离了,它们的分离意味着请求的动静分离变为可能:httpd和php-fpm分别运行在不同服务器上。动静分离后,压力也分散到各自的服务器上。
要让php-fpm以这种方式运行,需要在编译的./configure配置选项中添加"--enable-fpm"选项。当然,还得启动php-fpm服务。例如:
service php-fpm start
这样php-cgi进程就开放着端口(默认9000)等待httpd转发动态请求。要让httpd能够转发请求到php-cgi上,需要在httpd.conf中关闭正向代理,并设置fastcgi协议代理参数。例如,转发到192.168.100.54主机上的php-fpm。
# 加载代理模块 LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so # 添加MIME类型 AddType application/x-httpd-php .php AddType application/x-httpd-php-source .phps # 在需要转发的虚拟主机中配置转发代理 ProxyRequests off ProxyPassMatch ^/(.*\.php)$ fcgi://192.168.100.54:9000/usr/local/apache/htdocs/$1
随着技术的不断升级,单纯的Apache加php模块的方式已不再主流,而是替换为Apache加php_cgi,以及后来的php_fcgi和nginx加php-fpm的方法,可以看下图
2.1 CLI模式
PHP-CLI是PHP Command Line Interface的简称,如同它名字的意思,就是PHP在命令行运行的接口,区别于在Web服务器上运行的PHP环境(PHP-CGI,ISAPI等)。 也就是说,PHP不单可以写前台网页,它还可以用来写后台的程序。 PHP的CLI Shell脚本适用于所有的PHP优势,使创建要么支持脚本或系统甚至与GUI应用程序的服务端,在Windows和Linux下都是支持PHP-CLI模式的。
【优点】
1)使用多进程,子进程结束以后,内核会负责回收资源;
2)使用多进程,子进程异常退出不会导致整个进程Thread退出,父进程还有机会重建流程;
3)一个常驻主进程,只负责任务分发,逻辑更清楚。
我们在Linux下经常使用"php –m"查找PHP安装了那些扩展就是PHP命令行运行模式;有兴趣的同学可以输入"php –h"去深入研究该运行模式。