在上一篇文章: 「php之CGI、FastCGI 和 php-fpm」 中说明了,
cgi
和fastcgi
的关系和用途以及php-cgi
和php-fpm
又分别是什么,这篇文章主要说明一下nginx 和 php-fpm 是如何通信的
。
一、进程间的通信方式
nginx
和 php-fpm
作为两组 master-worker
模式的进程服务,两者之间的交互必然涉及 进程间通信
,先来看下 常见的 6 中进程通信
方式。
1. 管道:pipe
和 named pipe
- 两者都是半双工通信,即:通信只能有一个方向,一个写另一个读,不能双向读写。
- 是一种特殊的文件,使用 read 和 write 进行读写,区别是
pipe
不属于操作系统,只存在于内存当中。 -
pipe
和named pipe
的区别是:-
pipe
只能在父子进程或兄弟进程间使用 -
named pipe
则在任何两个毫无关系的进程间使用
-
2. 信号:signal
- 信号是在软件层次上对中断机制的一种模拟。在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。
- 信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
- 进程可以通过三种方式来响应一个信号:
- 忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及SIGSTOP;
- 捕捉信号。通过
signal
和sigaction
定义信号处理函数,当信号发生时,执行相应的处理函数; - 执行缺省操作,Linux对每种信号都规定了默认操作。
3. 消息队列:message queue
- 消息队列是消息的链表,存放在内核中,并由消息队列标识符标识(队列ID)
- 消息队列克服了上面两种方式的缺点:
- 信号传递信息少
- 管道只能承载无格式字节流以及缓冲区大小受限
- 消息队列是UNIX下不同进程之间可实现共享资源的一种机制。UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程.
- 通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序。
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
4. 信号量:semaphore
- 在内核中创建一个信号量数组,数组的元素(信号量)都是1。
- 使用P操作进行-1,使用V操作+1:
- P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执⾏。
- V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运⾏。如果没有进程因等待sv⽽挂起,就给它加1。
- PV操作用于同一进程,实现互斥。PV操作用于不同进程,实现同步。
5. 共享内存:shared memory
- 多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。
- 需要解决两个问题:
- 怎样提供共享内存?
- 怎样维护共享内存的互斥访问?
- 通常和信号量一起使用,来同步对共享内存的访问。
6. 套接字:socket
- 客户/服务器(即要进行通信的两个进程)既可以在本地单机上进行,也可以跨网络进行。
- 套接字的特性由3个属性确定,它们分别是:域、类型和协议
- 域,指定套接字通信中使用的网络介质。
-
AF_INET
表示Internet
网络,需要用到服务器的ip
和port
作为通信的重点。当然,服务器必须在开始通信前,绑定好端口,并等待客户端连接。 -
AF_UNIX
表示UNIX
文件系统,本质上是对文件的读写,需要指明文件的路径。
-
- 类型包含流
stream
和数据报datagram
两种:-
SOCK_STREAM
表示stream
类型,是一个有序、可靠、双向字节流连接,可以确保不会丢失、重复或乱序到达,而且还包含一个出错后重新发送
的机制 -
SOCK_DGRAM
表示datagram
类型,不需要建立和维持一个连接,以UDP/IP
协议实现。对数据长度有限制,且可能会丢失、复制或错乱到达,但速度很高。
-
- 协议。只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。通常只需要使用默认值。
- 域,指定套接字通信中使用的网络介质。
二、 nginx
和 php-fpm
中 socket
的两种域
nginx
和 php-fpm
间的通信使用的就是上述的 套接字(socket)
方案,根据 socket
中 域
的不同,分为 unix socket
和 tcp socket
两种配置方案。
1. unix socket
- nginx 方面需要指定
fastcgi_pass unix:/xxx/xxx/xxx.sock
,如:
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
}
- 相应地,fpm 方面需要指定
listen = /xxx/xxx/xxx.sock
,如:
listen = /var/run/php-fpm.sock
2. tcp socket
- nginx 方面需要指定
fastcgi_pass ip:port
,如:
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}
- 相应地,fpm 方面需要指定
listen = ip:port
,如:
listen = 127.0.0.1:9000
- 值得一提的是:在
tcp socket
下,fastcgi_pass
可以是一个带有权重的集群
,如:
upstream api_fpm {
server ip1:port1 weight=x1;
server ip2:port2 weight=x2;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;;
fastcgi_pass api_fpm;
fastcgi_index index.php;
}
3. unix socket
和 tcp socket
方案对比
-
unix socket
基于本地.sock
文件通信,省去底层网络协议传输的消耗,更高效。 -
tcp socket
配合nginx 的 upstream
实现了集群部署,更利于水平扩展。 - 基于上述特点:
- 不需要集群,追求快速影响时,选择
unix socket
。 - 更注重服务稳定性和可扩展性时,选择
tcp socket
。
- 不需要集群,追求快速影响时,选择
网友评论