mod_php、FastCGI等PHP运行方式分析
PHP运行方式
php默认提供了很多种SAPI,常见的给apache的mod_php5,CGI,给IIS的ISAPI,还有Shell的CLI。
对于一个基于apache的php应用,其运行流程可以简单归结如下:
apache -> httpd -> mod_php/fastcgi -> sapi -> php
1、CLI命令模式:Command Line Interface,就是命令行接口,例如可以在控制台或者是shell中键入命令:
php -f index.php
然后获取输出
2、CGI:
公共网关接口(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上。在服务器环境中,为“程序”提供标准的接口,通过这个接口,“程序 ”可以对服务器与客户端交换的信息做一些事情 。“程序 ”的语言并没有要求。程序对接口进行操作。服务器要支持CGI就要提供CGI中要求的环境变量,或者还有别的。
HTTP Server和一个独立的进程之间的协议,把HTTP Request的Header设置成进程的环境变量,HTTP Request的正文设置成进程的标准输入,而进程的标准输出就是HTTP Response包括Header和正文。
这个Web服务器使用了UNIX shell环境变量来保存从Web服务器传递出去的参数,然后生成一个运行CGI的独立进程。
不同类型语言写的程序只要符合cgi标准,就能作为一个cgi程序与web服务器交互
以CGI方式运行时,web server将用户请求以消息的方式转交给PHP独立进程,PHP与web服务之间无从属关系。
个人理解:CGI规定了php与web server交流的规则,相当于执行了response = exec("php -f index.php -url=xxx -cookie=xxx -xxx=xxx")。
关于CGI与CLI区别可以查看官方文档说的挺不错的:http://php.net/manual/zh/features.commandline.php ,文中阐述了CGI与CLI的显著区别。
CLI SAPI 与 CGI SAPI 不同,其输出没有任何头信息。
尽管 CGI SAPI 提供了取消 HTTP 头信息的方法,但在 CLI SAPI 中并不存在类似的方法以开启 HTTP 头信息的输出。
CLI 默认以安静模式开始,但为了保证兼容性,-q 和 --no-header 参数为了向后兼容仍然保留,使得可以使用旧的 CGI 脚本。
在运行时,不会把工作目录改为脚本的当前目录(可以使用 -C 和 --no-chdir 参数来兼容 CGI 模式)。
出错时输出纯文本的错误信息(非 HTML 格式)。
3、FastCGI:
FastCGI是交互程序与Web服务器通用的协议接口,是早期CGI(Common Gateway Interface)的一个变种。
mod_fastcgi是apache支持fastcgi协议的模块,基于mod_fastcgi的fastcgi应用一共有三种配置方式:静态、动态和远程。
其他Web服务器,如lighttpd, nginx,甚至微软的IIS也都能使用FastCGI。
使用FastCGI,可以同时设置多个版本的PHP,这在某些情况下非常有用。
FastCGI还利用suexec来支持不同的用户用自己的PHP的实例。这个特性对于在共享环境下提高安全性尤其重要。
CGI有很多缺点,每接收一个请求就要fork一个进程处理,只能接收一个请求作出一个响应。请求结束后该进程就会结束。
而FastCGI会事先启动起来,作为一个cgi的管理服务器存在,预先启动一系列的子进程来等待处理,然后等待web服务器发过来的请求,一旦接受到请求就交由子进程处理,这样由于不需要在接受到请求后启动cgi,会快很多。
FastCGI使用进程/线程池来处理一连串的请求。这些进程/线程由FastCGI服务器管理,而不是Web服务器。
当进来一个请求时,Web服务器把环境变量和这个页面请求通过一个Socket长连接传递给FastCGI进程。
FastCGI像是一个常驻型的CGI,它可以一直执行,在请求到达时不会花费时间去fork一个进程来处理(这是CGI最为人诟病的fork-and-execute模式)。正是因为它只是一个通信协议,它还支持分布式的运算,即FastCGI程序可以在网站服务器以外的主机上执行并且接受来自其他网站服务器的请求。
FastCGI是基于cgi架构的扩展,他的核心思想就是在web server和具体cgi程序之间建立一个智能的可持续的中间层,统管cgi程序的运行,这样web server只需要将请求提交给这个层,这个层再派生出几个可复用的cgi程序实例,然后再把请求分发给这些实例,这些实例是可控的,可持续,可复用的, 因此一方面避免了进程反复fork,另一方面又可以通过中间层的控制和探测机制来监视这些实例的运行情况,根据不同的状况fork或者回收实例,达到灵活 性和稳定性兼得的目的。
FastCGI的主要优点是把动态语言和web server分离开来。这种技术允许把web server和动态语言运行在不同的主机上,以大规模扩展和改进安全性而不损失生产效率。
基于mod_fastcgi方式的php应用,其典型工作流程如下
一般情况下,FastCGI的整个工作流程是这样的:
1)Web server启动时载入FastCGI进程管理器
2)FastCGI进程管理器解析配置文件,初始化执行环境,启动一个master主进程和start_servers个CGI子进程worker(可见多个php-cgi),主进程管理fastcgi子进程,fastcgi子进程等待来自Web Server的连接。
3)当请求Web server时,Web server通过socket请求FastCGI进程管理器,FastCGI进程管理器选择并连接到一个子进程CGI解释器,Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi
4)FastCGI子进程处理请求完成后将标准输出和错误从同一连接返回给Web server,当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待处理来自FastCGI进程管理器的下一个连接,在CGI模式中,php-cgi在此便退出了。
PHP-FPM是一个PHP FastCGI的进程管理器。
PHP-FPM可以和任何支持远端FastCGI的web server一起工作,类似于lighty下Spwn-cgi。
它的功能包括:
◆ 支持平滑停止/启动的高级进程管理功能;
◆ 可以工作于不同的 uid/gid/chroot环境下,并监听不同的端口和使用不同的php.ini配置文件(可取代safe_mode的设置);
◆ stdout 和 stderr 日志记录;
◆ 在发生意外情况的时候能够重新启动并缓存被破坏的 opcode;
◆ 文件上传优化支持;
◆ "慢日志" - 记录脚本(不仅记录文件名,还记录 PHP backtrace 信息,可以使用ptrace或者类似工具读取和分析远程进程的运行数据)运行所导致的异常缓慢;
◆ fastcgi_finish_request() 特殊功能:用于在请求完成和刷新数据后,继续在后台执行耗时的工作(录入视频转换、统计处理等);
◆ 动态/静态子进程产生;
◆ 基本 SAPI 运行状态信息(类似Apache的 mod_status);
◆ 基于 php.ini 的配置文件。
4、mod_php:
对于apache端php的配置,我们最常用的就是mod_php, 它把PHP做为APACHE一个内置模块。
让apache http服务器本身能够支持PHP语言,不需要每一个请求就启动PHP解释器来解释PHP。
当有一个php请求过来,直接在httpd进程里完成了php的解释运行,将结果返回,
Apache不会调用任何外部的PHP进程,因此这种方式使Apache与PHP能更好的通信。
但是,当以这种方式运行PHP的时候,哪怕Apache提供的仅仅是静态的资源(如HTML),
Apache的每个子进程也都会载入 mod_php,导致了比正常情况下更多的内存开销。
以这种方式运行的另一个缺点是,它仅能与Apache一起配合工作。
在CGI模式下,如果修改了PHP.INI的配置文件,不用重启web服务便可生效,而mod_php模块模式下则需要重启web服务。
以mod_php模式运行PHP,意味着php是作为apache的一个模块来启动的,因此只有在apache启动的时候会读取php.ini配置文件并加载扩展模块,在apache运行期间是不会再去读取和加载扩展模块的。