本文从Nginx与FPM的工作机制出发,探讨配置背后的原理,让我们真正理解Nginx与PHP是如何协同工作的。要说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是一个PHP进程管理器,包含master进程和worker进程两种进程:master进程只有一个,负责监听端口,接收来自Web
Server的请求,而worker进程则一般有多个(具体数量根据实际需要配置),每个进程内部都嵌入了一个PHP解释器,是PHP代码真正执行的地方,下图是我本机上fpm的进程情况,1一个master进程,3个worker进程:
从FPM接收到请求,到处理完毕,其具体的流程如下:
1.FPM的master进程接收到请求
2.master进程根据配置指派特定的worker进程进行请求处理,如果没有可用进程,返回错误,这也是我们配合Nginx遇到502错误比较多的原因。
3.worker进程处理请求,如果超时,返回504错误
4.请求处理结束,返回结果
FPM从接收到处理请求的流程就是这样了,那么Nginx又是如何发送请求给fpm的呢?这就需要从Nginx层面来说明了。
我们知道,Nginx不仅仅是一个Web服务器,也是一个功能强大的Proxy服务器,除了进行http请求的代理,也可以进行许多其他协议请求的代理,包括本文与fpm相关的fastcgi协议。为了能够使Nginx理解fastcgi协议,Nginx提供了fastcgi模块来将http请求映射为对应的fastcgi请求。
Nginx的fastcgi模块提供了fastcgi_param指令来主要处理这些映射关系,下面Ubuntu下Nginx的一个配置文件,其主要完成的工作是将Nginx中的变量翻译成PHP中能够理解的变量。
除此之外,非常重要的就是fastcgi_pass指令了,这个指令用于指定fpm进程监听的地址,Nginx会把所有的php请求翻译成fastcgi请求之后再发送到这个地址。下面一个简单的可以工作的Nginx配置文件:
在这个配置文件中,我们新建了一个虚拟主机,监听在80端口,Web根目录为/home/rf/projects/wordpress。然后我们通过location指令,将所有的以.php结尾的请求都交给fastcgi模块处理,从而把所有的php请求都交给了fpm处理,从而完成Nginx到fpm的闭环。
如此以来,Nginx与FPM通信的整个流程应该比较清晰了吧。