工作中考虑到PHP-FPM效率,发现PHP-FPM和NGINX的进程通信不止配置端口这一种方式:bowtie:
Nginx和PHP-FPM的进程间通信有两种方式,一种是TCP,一种是UNIX Domain Socket.
其中TCP是IP加端口,可以跨服务器.而UNIX Domain Socket不经过网络,只能用于Nginx跟PHP-FPM都在同一服务器的场景.
介绍Unix Domain Socket
Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信。socket 原本是为网络通讯设计的,但后来在 socket 的框架上发展出一种 IPC 机制,就是 UNIX domain socket。虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
UNIX domain socket 是全双工的,API 接口语义丰富,相比其它 IPC 机制有明显的优越性,目前已成为使用最广泛的 IPC 机制,比如 X Window 服务器和 GUI 程序之间就是通过 UNIX domain socket 通讯的。
Unix domain socket 是 POSIX 标准中的一个组件,所以不要被名字迷惑,linux 系统也是支持它的。
用哪种取决于你的PHP-FPM配置:
方式1:
php-fpm.conf: listen = 127.0.0.1:9000
nginx.conf: fastcgi_pass 127.0.0.1:9000;
方式2:
php-fpm.conf: listen = /tmp/php-fpm.sock
nginx.conf: fastcgi_pass unix:/tmp/php-fpm.sock;
其中php-fpm.sock是一个文件,由php-fpm生成,类型是srw-rw----
创建文件:touch php-fpm.sock
创建套接字文件:nc -Ul php-fpm.sock
r = 4
w = 2
x = 1
生成权限:chmod 660 /tmp/php-fpm.sock
注意: 需要配置权限
nginx.conf
- user www www
- worker_processes auto
php-fpm.conf
php-fpm.conf 走 sock形式,需要开启监听
- listen.owner = www
- listen.group = www
- listen.mode = 0660
文件属性
d 开头是: 目录文件。
l 开头是: 符号链接(指向另一个文件,类似于瘟下的快捷方式)。
s 开头是: 套接字文件(sock)。
b 开头是: 块设备文件,二进制文件。
c 开头是: 字符设备文件。
p 开头是: 命名管道文件。
UNIX Domain Socket可用于两个没有亲缘关系的进程,是目前广泛使用的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的.这种通信方式是发生在系统内核里而不会在网络里传播.
UNIX Domain Socket和长连接都能避免频繁创建TCP短连接而导致TIME_WAIT连接过多的问题.
对于进程间通讯的两个程序,UNIX Domain Socket的流程不会走到TCP那层,直接以文件形式,以stream socket通讯.
如果是TCP Socket,则需要走到IP层,对于非同一台服务器上,TCP Socket走的就更多了.
UNIX Domain Socket:
Nginx <=> socket <=> PHP-FPM
TCP Socket(本地回环):
Nginx <=> socket <=> TCP/IP <=> socket <=> PHP-FPM
TCP Socket(Nginx和PHP-FPM位于不同服务器):
Nginx <=> socket <=> TCP/IP <=> 物理层 <=> 路由器 <=> 物理层 <=> TCP/IP <=> socket <=> PHP-FPM
像mysql命令行客户端连接mysqld服务也类似有这两种方式:
# 使用Unix Socket连接(默认):
mysql -uroot -p --protocol=socket --socket=/tmp/mysql.sock
# 使用TCP连接:
mysql -uroot -p --protocol=tcp --host=127.0.0.1 --port=3306