作为一个phper,一直会接触到php、nignx等的相关配置,相关的名词比如PHP-FPM、CGI、Fast CGI、SAPI等等应该都或多或少接触过,但自己对于这些知识点的掌握其实相对比较分散且形成不了一定的关系,于是在网上搜了相关的文章并结合自己的一些理解,整理成此文,便于记录。
首先,先看一个最简单的服务器请求和响应的流程
在这个例子中,Web Server(如Nginx)只是内容的分发者,如果客户端请求的是 index.html等静态文件,那么Web Server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。
如果请求的是php文件,nginx无法直接处理,就会去配置文件nginx中寻找是否有对于php文件的配置
server
{
listen 80 default_server;
server_name _;
index index.html index.htm index.php;
root /home/wwwroot/test/public;
#error_page 404 /404.html;
location ~ [^/]\.php(/|$)
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
...
在nginx.conf文件中,大家可以发现有这么一段配置,如果是php文件的请求,就会分发到这个逻辑中。
这里定义的是与php解析器进行通讯的一些配置参数,其中fastcgi_pass参数约定了nginx和php进行通讯的socket是unix:/tmp/php-cgi.sock,后文会讲到php同时也会对应的监听这个端口
PS:部分配置文件中这个地址会是一个IP+端口号的TCP形式,TCP可以跨服务器,而UNIX Domain Socket不经过网络层,只能用于Nginx跟PHP-FPM都在同一服务器的场景
这样子友谊的小桥就这样顺利的搭建起来了。现在小桥搭建好了,剩下的就是通讯的数据格式的统一了,这时候需要用到Fast-cgi协议,这个协议约定了这两者通讯的数据格式
CGI:是 Web Server 与 Web Application 之间数据交换的一种协议,因为其每次请求都要执行fork-and-execut的流程,所以存在较大的性能瓶颈,现在已经很少使用
FastCGI:同 CGI,是一种通信协议,但比 CGI 在效率上做了一些优化,采用了常驻(long-live)型来减少系统的开销,使得性能大大提升
前面说过Fast CGI只是一种协议(看到有不少文章会将这是一个应用程序,其实是不对的),那遵循这个协议的实现者就是我们熟悉的PHP-FPM(FastCGI Process Manager),它的架构是由一个manager进程负责管理一个进程池,进程池中就是子进程php-cgi
打开php安装目录下的php-fpm.conf,可以看到有以下一段参数配置
listen = /tmp/php-cgi.sock
listen.backlog = -1
listen.allowed_clients = 127.0.0.1
listen.owner = www
可以看到php-fpm下同样监听了/tmp/php-cgi.sock这个socket,这和前面nginx.conf的配置是对应的
于是请求最后就交由到FastCGI子进程来进行处理,FastCGI子进程完成处理后,将标准输出和错误信息从同一连接返回Web Server进行输出
所以一个php请求的自上而下的流程如下图:
这里有一个名词放在文末将可能会更加的便于理解,大家可以看到我在图中将CGI包含在一个叫SAPI的类型下,那什么是SAPI呢?下面的解释引用至鸟哥的博客
SAPI: Server abstraction API,研究过PHP架构的同学应该知道这个东东的重要性,它提供了一个接口,使得PHP可以和其他应用进行交互数据
前面我们讲过的Fast CGI,还有其他比如shell的CLI,以及apache的mod_php5,都属于SAPI的范畴,目的是为了让各个服务器抽象层之间遵守着相同的约定,使php本身和上层应用解耦隔离,使php的可移植性更强。