深入理解PHP之:Nginx与FPM的工作机制
理解了基本的配置Nginx+FPM,要善于从Nginx与FPM的工作机制出发,探究背后的原理。
- 参考:https://segmentfault.com/a/1190000004853890
- CGI、FastCGI和PHP-FPM关系图解 :http://www.awaimai.com/371.html
- 我相信,要成为优秀的开发者,你必须对你每天都用的底层的软件系统有进一步的理解,包括编程语言、编译器和解释器、数据库和操作系统、WEB服务器和WEB框架
- 子曰:闻之我也野,视之我也饶,行之我也明
web服务器,cgi及php-fpm之间关系
web server(比如说nginx)只是内容的分发者。比如,如果请求
/index.html
,那么web server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。好了,如果现在请求的是/index.php
,根据配置文件,nginx知道这个不是静态文件,需要去找PHP解析器来处理,那么他会把这个请求简单处理后交给PHP解析器。Nginx会传哪些数据给PHP解析器呢?url要有吧,查询字符串也得有吧,POST数据也要有,HTTP header不能少吧,好的,CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在PHP代码中使用的用户从哪里来的。当web server收到
/index.php
这个请求后,会启动对应的CGI程序,这里就是PHP的解析器(fpm?)。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程。web server再把结果返回给浏览器。好了,CGI是个协议,跟进程什么的没关系。那fastcgi又是什么呢?Fastcgi是用来提高CGI程序性能的。
CGI和FCGI
要说 Nginx 与 PHP 是如何协同工作的,首先得说 CGI (Common Gateway Interface) 和 FastCGI 这两个协议。
CGI 是
Web Server
与后台语言交互的协议,有了这个协议,开发者可以使用任何语言处理 Web Server 发来的请求,动态的生成内容。但 CGI 有一个致命的缺点,那就是每处理一个请求都需要 fork 一个全新的进程,随着 Web 的兴起,高并发越来越成为常态,这样低效的方式明显不能满足需求。就这样,FastCGI 诞生了,CGI 很快就退出了历史的舞台。FastCGI,顾名思义为更快的 CGI,它允许在一个进程内处理多个请求,而不是一个请求处理完毕就直接结束进程,性能上有了很大的提高。至于 FPM (FastCGI Process Manager),它是 FastCGI 的实现,任何实现了 FastCGI 协议的 Web Server 都能够与之通信。FPM 之于标准的 FastCGI,也提供了一些增强功能,具体可以参考官方文档:PHP: FPM Installation。
FPM
至于 FPM (FastCGI Process Manager),它是 FastCGI 的实现,任何实现了 FastCGI 协议的 Web Server 都能够与之通信。FPM 之于标准的 FastCGI,也提供了一些增强功能,具体可以参考官方文档:PHP: FPM Installation。
FPM 是一个 PHP 进程管理器,包含 master 进程和 worker 进程两种进程:master 进程只有一个,负责监听端口,接收来自 Web Server 的请求,而 worker 进程则一般有多个 (具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方,下图是我本机上 fpm 的进程情况,1一个 master 进程,3个 worker 进程:
从 FPM 接收到请求,到处理完毕,其具体的流程如下:
- FPM 的 master 进程接收到请求
- master 进程根据配置指派特定的 worker 进程进行请求处理,如果没有可用进程,返回错误,这也是我们配合 Nginx 遇到502错误比较多的原因。
- worker 进程处理请求,如果超时,返回504错误
- 请求处理结束,返回结果
nginx发送请求给fpm
FPM 从接收到处理请求的流程就是这样了,那么 Nginx 又是如何发送请求给 fpm 的呢?这就需要从 Nginx 层面来说明了。
我们知道,Nginx 不仅仅是一个 Web 服务器,也是一个功能强大的 Proxy 服务器,除了进行 http 请求的代理,也可以进行许多其他协议请求的代理,包括本文与 fpm 相关的 fastcgi 协议。为了能够使 Nginx 理解 fastcgi 协议,Nginx 提供了 fastcgi 模块来将 http 请求映射为对应的 fastcgi 请求。
Nginx 的 fastcgi 模块提供了 fastcgi_param 指令来主要处理这些映射关系。
除此之外,非常重要的就是 fastcgi_pass 指令了,这个指令用于指定 fpm 进程监听的地址,Nginx 会把所有的 php 请求翻译成 fastcgi 请求之后再发送到这个地址,下面一个简单的可以工作的 Nginx 配置文件:
在这个配置文件中,我们新建了一个虚拟主机,监听在 80 端口,Web 根目录为 /home/rf/projects/wordpress。然后我们通过 location 指令,将所有的以 .php 结尾的请求都交给 fastcgi 模块处理,从而把所有的 php 请求都交给了 fpm 处理,从而完成 Nginx 到 fpm 的闭环。
一张图看清webservice(nginx)、cgi、php-cgi的关系
over
PHP生命周期和Zend引擎
从上面的文字,我们认识到
该文章讲述了php脚本的执行生命周期:http://www.php-internals.com/book/?p=chapt02/02-01-php-life-cycle-and-zend-engine