看完这篇文章,你可以知道
- PHP-CGI 是 PHP 解析器
- CGI 是一种协议
- Fast-CGI 是 CGI 的一个变种
- PHP-FPM 是对 Fast-CGI 的实现,是对 PHP-CGI 进程的管理
- Nginx 和 PHP-FPM 之间的通信方式
Nginx 与 PHP-FPM
Nginx(服务器)是内容的分发者,Nginx 启动后会监听某个指定的端口,等待客户端请求。如果通过解析 URI 得知客户端请求的是/index.html
文件,服务器会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。如果现在请求的是/index.php
,根据配置文件,服务器知道这不是静态文件,需要去找 PHP 解析器 (PHP-CGI)来处理。PHP-CGI 收到/index.php
这个请求后,会解析 php.ini 文件,初始化执行环境,然后处理请求,再以规定 CGI 规定的格式返回处理后的结果,退出进程。Nginx 再把结果返回给浏览器。
Nginx 调用 PHP-CGI 时会传第必要的信息如 URI、URL 参数、POST、HTTP header 等,通用网关接口 (CGI ) )规定了从 Nginx 到 PHP-CGI 之间的数据传输格式。
PHP-CGI 接收到 CGI 传来的数据后:环境初始化 –> 处理请求 –> 返回结果 –> 杀死进程 。每个请求都将对应一个 PHP-CGI 进程,因此导致服务器性能下降,并发不高。因此出现了一种新的协议叫 快速通用网关接口(FastCGI),FastCGI 的主要目标是减少 Web 服务器和 CGI 程序之间通信的开销,允许服务器一次处理更多的网页请求。
PHP-FPM 就是 FastCGI 协议的实现,对于 Fast-CGI 程序,不是每个请求都创建一个进程,PHP-FPM 会先启一个 Master 进程 –> 解析配置文件 –> 初始化执行环境 –> 启动多个 Worker。每个 Worker 都是一个 PHP-CGI,当请求过来时,Master 会将请求交给一个 Worker,然后立即可以接受下一个请求。PHP-FPM 对 PHP-CGI 进程进行管理,当 Worker 不够用时,Master 可以根据配置预先启动几个Worker ;当然空闲 Worker 太多时,也会停掉一些,这样就提高了性能,也节约了资源。
Nginx 与 PHP-FPM 通信机制与配置
Nginx 和 FastCGI 的通信方式有两种,一种是 TCP socket,一种是 Unix domain socket 。连接示意图如下:
配置方式
TCP通信配置
第一步,编辑 Nginx 配置文件 /path/to/nginx/conf/your-stie.conf
如果 PHP-FPM 和 Nginx 在同一台机器上,将 fastcgi_pass
参数修改为127.0.0.1:9000
,不在同一台机器时,将127.0.0.1
替换为 PHP-FPM 所在机器的 IP, 如下:
1 | location ~ \.php$ { |
第二步,编辑PHP-FPM 配置文件 /path/to/php/etc/php-fpm.conf
将 listen
参数修改为 your-php-fpm-ip:9000
,如下:
1 | listen = 127.0.0.1:9000 |
第三步,重启或重新载入 Nginx 和 PHP-FPM 的配置
1 | service nginx reload |
Unix socket 配置方式
Unix socket其实严格意义上应该叫 Unix domain socket,它是 *nix 系统进程间通信(IPC)的一种被广泛采用方式,以文件(一般是 .sock )作为 socket 的唯一标识(描述符),需要通信的两个进程引用同一个 socket 描述符文件就可以建立通道进行通信了。
第一步,决定你的 socket 描述符文件的存储位置。
可以放在系统的任意位置,如果想要更快的通信速度,可以放在 /dev/shm下面,这个目录是所谓的 tmpfs,是RAM 可以直接使用的区域,所以,读写速度都会很快。
决定了文件位置,就要修改文件的权限了,要让 Nginx 和 PHP-FPM 对它都有读写的权限,可以这样:
1 | sudo touch /dev/shm/fpm-cgi.sock |
第二步,修改 PHP-FPM 配置文件 /path/to/php/etc/php-fpm.conf
1 | listen = /dev/shm/fpm-cgi.sock |
注意: 要注意根据并发调整 listen.backlog 参数的值,默认是128,在高并发下可以改为-1,表示可以无限使用连接,最大连接限制有操作系统层控制。如下可以修改限制:
1 | sudo echo 'net.core.somaxconn = 2048' >> /etc/sysctl.conf |
第三步,修改 Nginx 站点配置文件 /path/to/nginx/conf/your-stie.conf
1 | location ~ \.php$ { |
第四步,重启或重新载入 Nginx 和 PHP-FPM 的配置
1 | service nginx reload |
两种通信方式的分析和总结
从原理上来说,Unix socket 方式肯定要比 TCP 的方式快而且消耗资源少,因为 TCP 需要经过本地回环驱动,还要申请临时端口。
Unix socket 会显得不是那么稳定,当并发连接数爆发时,会产生大量的长时缓存,在没有面向连接协议支撑的情况下,大数据包很有可能就直接出错并不会返回异常。而 TCP 这样的面向连接的协议,多少可以保证通信的正确性和完整性。