Nginx 与 PHP-FPM 通信机制

看完这篇文章,你可以知道

  • 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 太多时,也会停掉一些,这样就提高了性能,也节约了资源。

img

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
2
3
4
5
6
7
location ~ \.php$ {
index index.php index.html index.htm;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
}

第二步,编辑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
2
3
4
service nginx reload
# kill all php-fpm
pgrep php-fpm | xargs kill
cd /path/to/php/sbin/ && ./php-fpm

Unix socket 配置方式

Unix socket其实严格意义上应该叫 Unix domain socket,它是 *nix 系统进程间通信(IPC)的一种被广泛采用方式,以文件(一般是 .sock )作为 socket 的唯一标识(描述符),需要通信的两个进程引用同一个 socket 描述符文件就可以建立通道进行通信了。

第一步,决定你的 socket 描述符文件的存储位置。

可以放在系统的任意位置,如果想要更快的通信速度,可以放在 /dev/shm下面,这个目录是所谓的 tmpfs,是RAM 可以直接使用的区域,所以,读写速度都会很快。

决定了文件位置,就要修改文件的权限了,要让 Nginx 和 PHP-FPM 对它都有读写的权限,可以这样:

1
2
3
sudo touch /dev/shm/fpm-cgi.sock
sudo chown www-data:www-data /dev/shm/fpm-cgi.sock
sudo chmod 666 /dev/shm/fpm-cgi.sock

第二步,修改 PHP-FPM 配置文件 /path/to/php/etc/php-fpm.conf

1
2
3
4
5
listen = /dev/shm/fpm-cgi.sock

; Set listen(2) backlog. A value of '-1' means unlimited.
; Default Value: 128 (-1 on FreeBSD and OpenBSD)
listen.backlog = -1

注意: 要注意根据并发调整 listen.backlog 参数的值,默认是128,在高并发下可以改为-1,表示可以无限使用连接,最大连接限制有操作系统层控制。如下可以修改限制:

1
2
sudo echo 'net.core.somaxconn = 2048' >> /etc/sysctl.conf
sudo sysctl -p

第三步,修改 Nginx 站点配置文件 /path/to/nginx/conf/your-stie.conf

1
2
3
4
5
6
7
location ~ \.php$ {
index index.php index.html index.htm;
include /etc/nginx/fastcgi_params;
fastcgi_pass /dev/shm/fpm-cgi.sock;
fastcgi_index index.php;
include fastcgi_params;
}

第四步,重启或重新载入 Nginx 和 PHP-FPM 的配置

1
2
3
4
service nginx reload
# kill all php-fpm
pgrep php-fpm | xargs kill
cd /path/to/php/sbin/ && ./php-fpm

两种通信方式的分析和总结

从原理上来说,Unix socket 方式肯定要比 TCP 的方式快而且消耗资源少,因为 TCP 需要经过本地回环驱动,还要申请临时端口。

Unix socket 会显得不是那么稳定,当并发连接数爆发时,会产生大量的长时缓存,在没有面向连接协议支撑的情况下,大数据包很有可能就直接出错并不会返回异常。而 TCP 这样的面向连接的协议,多少可以保证通信的正确性和完整性。

参考

http://xieminis.me/?p=216

http://www.cnblogs.com/tinywan/p/6625432.html

https://www.awaimai.com/371.html

本文标题:Nginx 与 PHP-FPM 通信机制

文章作者:Syncher

发布时间:2018年03月31日 - 22:03

最后更新:2018年08月14日 - 21:08

原始链接:https://0x400.com/2018-03-31-linux-nginx-fpm-communication-explaination.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。