nginx、php-fpm默认配置与性能–TCP socket还是unix domain socket

本文详细阐述了一个web游戏服务器架构的优化过程,包括使用nginx进行长连接与短连接的对比,以及如何通过nginx的ngx_http_upstream_keepalive模块减少端口占用和提高性能。此外,文章还探讨了在同一服务器上使用TCPsocket与unixdomainsocket的区别,并解释了localhost与127.0.0.1在MySQL连接时的不同行为。最后,作者分享了服务器配置更改后的架构图及改进点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类似经历
之所以多这篇文章兴趣这么高,是因为在前段时间,末学也经历了一件类似的优化历程,先简短的描述下我们的服务器架构。如图

一款webgame 粗略架构图

想必看到这幅架构图的同学,都比较熟悉吧,也比较简单。“最前面”的nginx 反代负责与玩家的http请求通讯,这里是长连接。在其与后端游戏大区通讯时,使用了短连接,也就是意味着,每处理用户的一个http请求,都要重新与后端的nginx建立一次TCP(http)请求,后端nginx处理完之后就关闭。后端的nginx与php在同一台服务器上,通讯配置如下:

01 //NGINX 反代
02 upstream server1 {
03     server  10.10.10.1   max_fails=2  fail_timeout=30s;  #app1
04     server  10.10.10.2   max_fails=2  fail_timeout=30s;  #app2
05 }
06  
07 // 后端NGINX
08 // Nginx 默认配置 http://trac.nginx.org/nginx/browser/nginx/trunk/conf/nginx.conf
09 location ~ \.php$ {
10     root           html;
11     fastcgi_pass   127.0.0.1:9000;
12     fastcgi_index  index.php;
13     fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
14     include        fastcgi_params;
15 }
16  
17 //PHP-FPM
18 //PHP-FPM 默认配置 https://github.com/php/php-src/blob/master/sapi/fpm/php-fpm.conf.in
19 ; The address on which to accept FastCGI requests.
20 ; Valid syntaxes are:
21 ;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific address on a specific port;
22 ;   'port'                 - to listen on a TCP socket to all addresses on a specific port;
23 ;   '/path/to/unix/socket' - to listen on a unix socket.
24 ; Note: This value is mandatory.
25 listen = 127.0.0.1:9000

在这个架构图中,反代承担这承上启下的作用,前面是用户,后面是web app服务器,长连接用户,短连接后端。若用户数在1W人,1W人与反代的连接,在反代服务器上都用80端口。但这1W人的每一个请求,反代都要重新使用服务器的端口与后端nginx的80创建tcp socket,来处理请求。若2MSL时间为1分钟以上,同时,玩家两次请求间隔很短,想我们游戏的服务器,两次请求间隔大约5秒(甚至2-3秒)。那么反代的端口,5秒用1W个,10秒2W,15秒3W,20秒4W,25秒5W,30秒6W!!!,前面已经用掉的端口还没被回收掉。那么将会有很多的用户请求被nginx反代接收之后,因没有端口资源而无法与后端nginx创建tcp连接。。。以游戏的其中一个大区为例:

关于这个问题,末学在新浪微博上请教过其他大牛,其中tengine负责人淘叔度前辈以及@120斤的大青蛙前辈告诉我,nginx将在1.1.4版本开始支持ngx_http_upstream_keepalive,3月1号左右,是1.1.16 dev版本,我们的运维团队稍微由于几天,之后在部分小区的服务器上适用了1.1.16,效果不错,Nginx反代上与目标服务器的80端口的TCP连接中处于ESTABLISHED状态的非常多,TIME_WAIT的几乎没有,很稳定。我们几乎计划为了这个性能的提升,决定用dev版了。接着nginx1.2Stable version也出来了,那么也就用这个版本了。至于反代上nginx与后端app server建立TCP连接个数,也就是端口数(满载情况下,维持ESTABLISHED状态)的为nginx worker_processes * ((upstream1 server * keepalive参数数量) + (upstream2 server * keepalive参数数量) + …),并不多。

如上,端口占用数少了,那么还有其他有点吗?先看一副 socket创建,监听、数据接收发送、关闭与客户端连接的socket流程图:

如上图,nginx反代跟后端nginx的形式跟php-fpm与mysqld socket的模型一样的。
nginx反代跟php-fpm 相对来说,就是客户端,这种做法,他们的每个新socket 请求的发起,都会跟着左边的流程走一遍,一遍又一遍。。。。每次的socket创建,端口等资源申请,与服务端的三次握手,关闭时的四次握手,端口的回收。。。。
改用长连接之后,如下图:

只有php-fpm(或者nginx反代)的子进程分别与mysqld创建1次TCP连接,之后都是send、recv数据的事情了,端口占用也是为数不多的几个(每个fpm子进程将与mysqld维持一个TCP长连接)。

同样,后端服务器的nginx与php-fpm的通讯也是如此,只是请求两没有反代那么大。区别就是IP地址是回环地址127.0.0.1。
既然是回环地址,那么两个服务都是在同一台机器上跑的,既然是同一台机器,为何不用进程间通讯的socket–unix domain socket呢?
socket是神马?摘抄一段描述:

Socket 可以被定义描述为两个应用通信通道的端点。一个 Socket 端点可以用 Socket 地址来描述, Socket 地址结构由 IP 地址,端口和使用协议组成( TCP or UDP )。http协议可以通过socket实现,socket在传输层上实现。从这个角度来说,socket介于应用层和传输层之间。但是socket作为一种进程通信机制,操作系统分配唯一一个socket号,是依赖于通信协议的,但是这个通信协议不仅仅是 tcp或udp,也可以是其它协议。

在同一台服务器上,用tcp socket与unix domain socket有什么区别?
如图所示,对于进程间通讯的两个程序,unix domain socket的流程不会走到TCP 那层,直接以文件形式,以stream socket通讯。如果是TCP socket,则需要走到IP层。

对于非同一台服务器上,TCP socket走的就更多了。

至于localhost\127.0.0.1以及网络IP他们之间的区别,无意中找到一篇博客写的是以mysql作为验证,来说明localhost不走TCP/IP层,跟127.0.0.1不一样。末学认为他理解错了。他的理由如下

(以下截图均在linux上,windows的没有unix domain socket)
mysql连接本机时,不加-h参数:

mysql连接本机时,加-h参数且值是localhost:

mysql连接本机时,加-h参数且值是127.0.0.1:

那位同学从mysql工具的使用方法、与结果的区别,来理解推导localhost与127.0.0.1的区别,这从方向上就存在问题,我更相信,这是mysql这个程序自己的行为,遇到-h参数没加,或者-h参数的值不是IP形式,且my.cnf里指定mysql的socket路径时,则直接使用unix domain socket来连接服务器,当然,这也是我的猜测,没有去验证,大家听听就好,别相信。

鉴于末学对以上的理解,将服务器的架构配置变更如下

01 //NGinx 反代配置
02 upstream server1 {
03         keepalive 10 single;
04         //参见nginx官方wiki,记得看E文版,中文版的还没更新 http://wiki.nginx.org/NginxHttpUpstreamModule
05         server 10.10.8.97  max_fails=2 fail_timeout=30s;  #app1
06         server 10.10.8.99  max_fails=2 fail_timeout=30s;  #app2
07         server 10.10.8.85  max_fails=2 fail_timeout=30s;  #app3
08 }
09  
10 //NGINX配置
11 //获取PHP扩展名的规则,适用于
12 location ~ ^([^.]+\.php)($|/.*) {
13     fastcgi_pass unix:/var/run/php5-fpm.sock;
14     fastcgi_index index.php;
15     include fastcgi_params;
16 }
17  
18 //php-fpm配置
19 ; Note: This value is mandatory.
20 listen = /var/run/php5-fpm.sock //与nginx 的fastcgi_pass的路径一致即可,目录要有相应读写权限

至此,优化还为完毕,若php-fpm与mysql使用mysql_pconnect的话,那么php-fpm的子进程生成模式最好用static模式,若为dynamic模式,可能会出现mysql连接数被占满的情况,这也跟mysql服务的连接超时时间有关,适当调整也容易避免。
不过,我们目前还没用mysql_pconnect,主要原因是我们的代码中,有些事务处理开启之后,对于代码的失败处理,忘记写回滚语句,在短连接的情况下,这个连接的销毁,哪怕客户端没提交ROLLBACK或者COMMIT指令,mysql会自动回滚之前的事务。但使用长连接之后,不同请求会使用同一个MYSQL连接句柄,每个事务开启都会禁用MYSQL的自动提交,即SET AUTOCOMMIT=0语句,这语句会提交之前的事务。对于我们代码忘记写回滚,而直接返回结果的情况下,这是会出大问题的,也是我们目前唯一没有使用MYSQL_pconnect的原因。(计划近期找到没有写回滚语句的代码,修复,继续使用mysql_pconnect)

其实还有,我们php-fpm使用了APC来缓存php file,以及 变量数据等,这些也是有优化的地方(如果有时间的话,则待续)。

回过头来再理解下文章开头那位同学给的解决办法,我仍不能从他给的理由中,理解长连接的缺点,哪怕是解决了TIME_WAIT的问题,但每次创建TCP socket ,连接到服务器时三次握手,关闭TCP socket时的四次握手 这些也是开销。当然,缩短2MSL的时间,也是更好利用服务器资源的一个好方法。

最后,我们调整优化的服务器架构图如下:

好像有点偏离这篇文章的标题了,其实我更想说我不能理解为啥nginx跟php-fpm给的默认配置中,都是TCP socket通讯的,为啥不默认给unix domain socket的默认配置呢?如果说为了方便非同一台服务器时的情况,但给的默认IP也是回环地址呀。
而且,nginx给默认配置中,对于uri请求中的php文件的处理,匹配规则还是老的,之前发生因为NGINX与PHP的配置而导致的安全问题,虽然不是nginx的错,但nginx也可给出更严谨的范例,但仍没有。

值得欣慰的是,在UBUNTU 12.4中,nginx的默认配置有了很大的改进,不管是匹配uri的规则,还是nginx与php-fpm的交互方式:

01 #location ~ \.php$ {
02 #       fastcgi_split_path_info ^(.+\.php)(/.+)$;    //赞1
03 #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
04 #
05 #       # With php5-cgi alone:
06 #       fastcgi_pass 127.0.0.1:9000;    //赞3
07 #       # With php5-fpm:
08 #       fastcgi_pass unix:/var/run/php5-fpm.sock;    //赞3
09 #       fastcgi_index index.php;
10 #       include fastcgi_params;
11 #}

PS:末学只是个web程序员,这些只是末学学习研究如上知识的总结,理解上难免有错,各位请海涵。


nginx、php-fpm默认配置与性能–TCP socket还是unix domain socket

前几天看到一篇博客,提到php所在服务器在大并发情况下,频繁创建TCP短连接,而其所在服务器的2MSL时间过长,导致没有端口可用,系统无法创建TCP socket,而大量报错。博主在后面给的解决方案是减少2MSL的时间,尽快清除TIME_WAIT状态的TCP连接,回收端口。同时,文章结尾写了不用长连接的理由,但这真的是最好的解决办法吗?有其他办法可以更好的做法吗?

类似经历
之所以多这篇文章兴趣这么高,是因为在前段时间,末学也经历了一件类似的优化历程,先简短的描述下我们的服务器架构。如图

一款webgame 粗略架构图

想必看到这幅架构图的同学,都比较熟悉吧,也比较简单。“最前面”的nginx 反代负责与玩家的http请求通讯,这里是长连接。在其与后端游戏大区通讯时,使用了短连接,也就是意味着,每处理用户的一个http请求,都要重新与后端的nginx建立一次TCP(http)请求,后端nginx处理完之后就关闭。后端的nginx与php在同一台服务器上,通讯配置如下:

01 //NGINX 反代
02 upstream server1 {
03     server  10.10.10.1   max_fails=2  fail_timeout=30s;  #app1
04     server  10.10.10.2   max_fails=2  fail_timeout=30s;  #app2
05 }
06  
07 // 后端NGINX
08 // Nginx 默认配置 http://trac.nginx.org/nginx/browser/nginx/trunk/conf/nginx.conf
09 location ~ \.php$ {
10     root           html;
11     fastcgi_pass   127.0.0.1:9000;
12     fastcgi_index  index.php;
13     fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
14     include        fastcgi_params;
15 }
16  
17 //PHP-FPM
18 //PHP-FPM 默认配置 https://github.com/php/php-src/blob/master/sapi/fpm/php-fpm.conf.in
19 ; The address on which to accept FastCGI requests.
20 ; Valid syntaxes are:
21 ;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific address on a specific port;
22 ;   'port'                 - to listen on a TCP socket to all addresses on a specific port;
23 ;   '/path/to/unix/socket' - to listen on a unix socket.
24 ; Note: This value is mandatory.
25 listen = 127.0.0.1:9000

在这个架构图中,反代承担这承上启下的作用,前面是用户,后面是web app服务器,长连接用户,短连接后端。若用户数在1W人,1W人与反代的连接,在反代服务器上都用80端口。但这1W人的每一个请求,反代都要重新使用服务器的端口与后端nginx的80创建tcp socket,来处理请求。若2MSL时间为1分钟以上,同时,玩家两次请求间隔很短,想我们游戏的服务器,两次请求间隔大约5秒(甚至2-3秒)。那么反代的端口,5秒用1W个,10秒2W,15秒3W,20秒4W,25秒5W,30秒6W!!!,前面已经用掉的端口还没被回收掉。那么将会有很多的用户请求被nginx反代接收之后,因没有端口资源而无法与后端nginx创建tcp连接。。。以游戏的其中一个大区为例:

关于这个问题,末学在新浪微博上请教过其他大牛,其中tengine负责人淘叔度前辈以及@120斤的大青蛙前辈告诉我,nginx将在1.1.4版本开始支持ngx_http_upstream_keepalive,3月1号左右,是1.1.16 dev版本,我们的运维团队稍微由于几天,之后在部分小区的服务器上适用了1.1.16,效果不错,Nginx反代上与目标服务器的80端口的TCP连接中处于ESTABLISHED状态的非常多,TIME_WAIT的几乎没有,很稳定。我们几乎计划为了这个性能的提升,决定用dev版了。接着nginx1.2Stable version也出来了,那么也就用这个版本了。至于反代上nginx与后端app server建立TCP连接个数,也就是端口数(满载情况下,维持ESTABLISHED状态)的为nginx worker_processes * ((upstream1 server * keepalive参数数量) + (upstream2 server * keepalive参数数量) + …),并不多。

如上,端口占用数少了,那么还有其他有点吗?先看一副 socket创建,监听、数据接收发送、关闭与客户端连接的socket流程图:

如上图,nginx反代跟后端nginx的形式跟php-fpm与mysqld socket的模型一样的。
nginx反代跟php-fpm 相对来说,就是客户端,这种做法,他们的每个新socket 请求的发起,都会跟着左边的流程走一遍,一遍又一遍。。。。每次的socket创建,端口等资源申请,与服务端的三次握手,关闭时的四次握手,端口的回收。。。。
改用长连接之后,如下图:

只有php-fpm(或者nginx反代)的子进程分别与mysqld创建1次TCP连接,之后都是send、recv数据的事情了,端口占用也是为数不多的几个(每个fpm子进程将与mysqld维持一个TCP长连接)。

同样,后端服务器的nginx与php-fpm的通讯也是如此,只是请求两没有反代那么大。区别就是IP地址是回环地址127.0.0.1。
既然是回环地址,那么两个服务都是在同一台机器上跑的,既然是同一台机器,为何不用进程间通讯的socket–unix domain socket呢?
socket是神马?摘抄一段描述:

Socket 可以被定义描述为两个应用通信通道的端点。一个 Socket 端点可以用 Socket 地址来描述, Socket 地址结构由 IP 地址,端口和使用协议组成( TCP or UDP )。http协议可以通过socket实现,socket在传输层上实现。从这个角度来说,socket介于应用层和传输层之间。但是socket作为一种进程通信机制,操作系统分配唯一一个socket号,是依赖于通信协议的,但是这个通信协议不仅仅是 tcp或udp,也可以是其它协议。

在同一台服务器上,用tcp socket与unix domain socket有什么区别?
如图所示,对于进程间通讯的两个程序,unix domain socket的流程不会走到TCP 那层,直接以文件形式,以stream socket通讯。如果是TCP socket,则需要走到IP层。

对于非同一台服务器上,TCP socket走的就更多了。

至于localhost\127.0.0.1以及网络IP他们之间的区别,无意中找到一篇博客写的是以mysql作为验证,来说明localhost不走TCP/IP层,跟127.0.0.1不一样。末学认为他理解错了。他的理由如下

(以下截图均在linux上,windows的没有unix domain socket)
mysql连接本机时,不加-h参数:

mysql连接本机时,加-h参数且值是localhost:

mysql连接本机时,加-h参数且值是127.0.0.1:

那位同学从mysql工具的使用方法、与结果的区别,来理解推导localhost与127.0.0.1的区别,这从方向上就存在问题,我更相信,这是mysql这个程序自己的行为,遇到-h参数没加,或者-h参数的值不是IP形式,且my.cnf里指定mysql的socket路径时,则直接使用unix domain socket来连接服务器,当然,这也是我的猜测,没有去验证,大家听听就好,别相信。

鉴于末学对以上的理解,将服务器的架构配置变更如下

01 //NGinx 反代配置
02 upstream server1 {
03         keepalive 10 single;
04         //参见nginx官方wiki,记得看E文版,中文版的还没更新 http://wiki.nginx.org/NginxHttpUpstreamModule
05         server 10.10.8.97  max_fails=2 fail_timeout=30s;  #app1
06         server 10.10.8.99  max_fails=2 fail_timeout=30s;  #app2
07         server 10.10.8.85  max_fails=2 fail_timeout=30s;  #app3
08 }
09  
10 //NGINX配置
11 //获取PHP扩展名的规则,适用于
12 location ~ ^([^.]+\.php)($|/.*) {
13     fastcgi_pass unix:/var/run/php5-fpm.sock;
14     fastcgi_index index.php;
15     include fastcgi_params;
16 }
17  
18 //php-fpm配置
19 ; Note: This value is mandatory.
20 listen = /var/run/php5-fpm.sock //与nginx 的fastcgi_pass的路径一致即可,目录要有相应读写权限

至此,优化还为完毕,若php-fpm与mysql使用mysql_pconnect的话,那么php-fpm的子进程生成模式最好用static模式,若为dynamic模式,可能会出现mysql连接数被占满的情况,这也跟mysql服务的连接超时时间有关,适当调整也容易避免。
不过,我们目前还没用mysql_pconnect,主要原因是我们的代码中,有些事务处理开启之后,对于代码的失败处理,忘记写回滚语句,在短连接的情况下,这个连接的销毁,哪怕客户端没提交ROLLBACK或者COMMIT指令,mysql会自动回滚之前的事务。但使用长连接之后,不同请求会使用同一个MYSQL连接句柄,每个事务开启都会禁用MYSQL的自动提交,即SET AUTOCOMMIT=0语句,这语句会提交之前的事务。对于我们代码忘记写回滚,而直接返回结果的情况下,这是会出大问题的,也是我们目前唯一没有使用MYSQL_pconnect的原因。(计划近期找到没有写回滚语句的代码,修复,继续使用mysql_pconnect)

其实还有,我们php-fpm使用了APC来缓存php file,以及 变量数据等,这些也是有优化的地方(如果有时间的话,则待续)。

回过头来再理解下文章开头那位同学给的解决办法,我仍不能从他给的理由中,理解长连接的缺点,哪怕是解决了TIME_WAIT的问题,但每次创建TCP socket ,连接到服务器时三次握手,关闭TCP socket时的四次握手 这些也是开销。当然,缩短2MSL的时间,也是更好利用服务器资源的一个好方法。

最后,我们调整优化的服务器架构图如下:

好像有点偏离这篇文章的标题了,其实我更想说我不能理解为啥nginx跟php-fpm给的默认配置中,都是TCP socket通讯的,为啥不默认给unix domain socket的默认配置呢?如果说为了方便非同一台服务器时的情况,但给的默认IP也是回环地址呀。
而且,nginx给默认配置中,对于uri请求中的php文件的处理,匹配规则还是老的,之前发生因为NGINX与PHP的配置而导致的安全问题,虽然不是nginx的错,但nginx也可给出更严谨的范例,但仍没有。

值得欣慰的是,在UBUNTU 12.4中,nginx的默认配置有了很大的改进,不管是匹配uri的规则,还是nginx与php-fpm的交互方式:

01 #location ~ \.php$ {
02 #       fastcgi_split_path_info ^(.+\.php)(/.+)$;    //赞1
03 #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
04 #
05 #       # With php5-cgi alone:
06 #       fastcgi_pass 127.0.0.1:9000;    //赞3
07 #       # With php5-fpm:
08 #       fastcgi_pass unix:/var/run/php5-fpm.sock;    //赞3
09 #       fastcgi_index index.php;
10 #       include fastcgi_params;
11 #}

PS:末学只是个web程序员,这些只是末学学习研究如上知识的总结,理解上难免有错,各位请海涵。


类似经历
之所以多这篇文章兴趣这么高,是因为在前段时间,末学也经历了一件类似的优化历程,先简短的描述下我们的服务器架构。如图

一款webgame 粗略架构图

想必看到这幅架构图的同学,都比较熟悉吧,也比较简单。“最前面”的nginx 反代负责与玩家的http请求通讯,这里是长连接。在其与后端游戏大区通讯时,使用了短连接,也就是意味着,每处理用户的一个http请求,都要重新与后端的nginx建立一次TCP(http)请求,后端nginx处理完之后就关闭。后端的nginx与php在同一台服务器上,通讯配置如下:

01 //NGINX 反代
02 upstream server1 {
03     server  10.10.10.1   max_fails=2  fail_timeout=30s;  #app1
04     server  10.10.10.2   max_fails=2  fail_timeout=30s;  #app2
05 }
06  
07 // 后端NGINX
08 // Nginx 默认配置 http://trac.nginx.org/nginx/browser/nginx/trunk/conf/nginx.conf
09 location ~ \.php$ {
10     root           html;
11     fastcgi_pass   127.0.0.1:9000;
12     fastcgi_index  index.php;
13     fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
14     include        fastcgi_params;
15 }
16  
17 //PHP-FPM
18 //PHP-FPM 默认配置 https://github.com/php/php-src/blob/master/sapi/fpm/php-fpm.conf.in
19 ; The address on which to accept FastCGI requests.
20 ; Valid syntaxes are:
21 ;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific address on a specific port;
22 ;   'port'                 - to listen on a TCP socket to all addresses on a specific port;
23 ;   '/path/to/unix/socket' - to listen on a unix socket.
24 ; Note: This value is mandatory.
25 listen = 127.0.0.1:9000

在这个架构图中,反代承担这承上启下的作用,前面是用户,后面是web app服务器,长连接用户,短连接后端。若用户数在1W人,1W人与反代的连接,在反代服务器上都用80端口。但这1W人的每一个请求,反代都要重新使用服务器的端口与后端nginx的80创建tcp socket,来处理请求。若2MSL时间为1分钟以上,同时,玩家两次请求间隔很短,想我们游戏的服务器,两次请求间隔大约5秒(甚至2-3秒)。那么反代的端口,5秒用1W个,10秒2W,15秒3W,20秒4W,25秒5W,30秒6W!!!,前面已经用掉的端口还没被回收掉。那么将会有很多的用户请求被nginx反代接收之后,因没有端口资源而无法与后端nginx创建tcp连接。。。以游戏的其中一个大区为例:

关于这个问题,末学在新浪微博上请教过其他大牛,其中tengine负责人淘叔度前辈以及@120斤的大青蛙前辈告诉我,nginx将在1.1.4版本开始支持ngx_http_upstream_keepalive,3月1号左右,是1.1.16 dev版本,我们的运维团队稍微由于几天,之后在部分小区的服务器上适用了1.1.16,效果不错,Nginx反代上与目标服务器的80端口的TCP连接中处于ESTABLISHED状态的非常多,TIME_WAIT的几乎没有,很稳定。我们几乎计划为了这个性能的提升,决定用dev版了。接着nginx1.2Stable version也出来了,那么也就用这个版本了。至于反代上nginx与后端app server建立TCP连接个数,也就是端口数(满载情况下,维持ESTABLISHED状态)的为nginx worker_processes * ((upstream1 server * keepalive参数数量) + (upstream2 server * keepalive参数数量) + …),并不多。

如上,端口占用数少了,那么还有其他有点吗?先看一副 socket创建,监听、数据接收发送、关闭与客户端连接的socket流程图:

如上图,nginx反代跟后端nginx的形式跟php-fpm与mysqld socket的模型一样的。
nginx反代跟php-fpm 相对来说,就是客户端,这种做法,他们的每个新socket 请求的发起,都会跟着左边的流程走一遍,一遍又一遍。。。。每次的socket创建,端口等资源申请,与服务端的三次握手,关闭时的四次握手,端口的回收。。。。
改用长连接之后,如下图:

只有php-fpm(或者nginx反代)的子进程分别与mysqld创建1次TCP连接,之后都是send、recv数据的事情了,端口占用也是为数不多的几个(每个fpm子进程将与mysqld维持一个TCP长连接)。

同样,后端服务器的nginx与php-fpm的通讯也是如此,只是请求两没有反代那么大。区别就是IP地址是回环地址127.0.0.1。
既然是回环地址,那么两个服务都是在同一台机器上跑的,既然是同一台机器,为何不用进程间通讯的socket–unix domain socket呢?
socket是神马?摘抄一段描述:

Socket 可以被定义描述为两个应用通信通道的端点。一个 Socket 端点可以用 Socket 地址来描述, Socket 地址结构由 IP 地址,端口和使用协议组成( TCP or UDP )。http协议可以通过socket实现,socket在传输层上实现。从这个角度来说,socket介于应用层和传输层之间。但是socket作为一种进程通信机制,操作系统分配唯一一个socket号,是依赖于通信协议的,但是这个通信协议不仅仅是 tcp或udp,也可以是其它协议。

在同一台服务器上,用tcp socket与unix domain socket有什么区别?
如图所示,对于进程间通讯的两个程序,unix domain socket的流程不会走到TCP 那层,直接以文件形式,以stream socket通讯。如果是TCP socket,则需要走到IP层。

对于非同一台服务器上,TCP socket走的就更多了。

至于localhost\127.0.0.1以及网络IP他们之间的区别,无意中找到一篇博客写的是以mysql作为验证,来说明localhost不走TCP/IP层,跟127.0.0.1不一样。末学认为他理解错了。他的理由如下

(以下截图均在linux上,windows的没有unix domain socket)
mysql连接本机时,不加-h参数:

mysql连接本机时,加-h参数且值是localhost:

mysql连接本机时,加-h参数且值是127.0.0.1:

那位同学从mysql工具的使用方法、与结果的区别,来理解推导localhost与127.0.0.1的区别,这从方向上就存在问题,我更相信,这是mysql这个程序自己的行为,遇到-h参数没加,或者-h参数的值不是IP形式,且my.cnf里指定mysql的socket路径时,则直接使用unix domain socket来连接服务器,当然,这也是我的猜测,没有去验证,大家听听就好,别相信。

鉴于末学对以上的理解,将服务器的架构配置变更如下

01 //NGinx 反代配置
02 upstream server1 {
03         keepalive 10 single;
04         //参见nginx官方wiki,记得看E文版,中文版的还没更新 http://wiki.nginx.org/NginxHttpUpstreamModule
05         server 10.10.8.97  max_fails=2 fail_timeout=30s;  #app1
06         server 10.10.8.99  max_fails=2 fail_timeout=30s;  #app2
07         server 10.10.8.85  max_fails=2 fail_timeout=30s;  #app3
08 }
09  
10 //NGINX配置
11 //获取PHP扩展名的规则,适用于
12 location ~ ^([^.]+\.php)($|/.*) {
13     fastcgi_pass unix:/var/run/php5-fpm.sock;
14     fastcgi_index index.php;
15     include fastcgi_params;
16 }
17  
18 //php-fpm配置
19 ; Note: This value is mandatory.
20 listen = /var/run/php5-fpm.sock //与nginx 的fastcgi_pass的路径一致即可,目录要有相应读写权限

至此,优化还为完毕,若php-fpm与mysql使用mysql_pconnect的话,那么php-fpm的子进程生成模式最好用static模式,若为dynamic模式,可能会出现mysql连接数被占满的情况,这也跟mysql服务的连接超时时间有关,适当调整也容易避免。
不过,我们目前还没用mysql_pconnect,主要原因是我们的代码中,有些事务处理开启之后,对于代码的失败处理,忘记写回滚语句,在短连接的情况下,这个连接的销毁,哪怕客户端没提交ROLLBACK或者COMMIT指令,mysql会自动回滚之前的事务。但使用长连接之后,不同请求会使用同一个MYSQL连接句柄,每个事务开启都会禁用MYSQL的自动提交,即SET AUTOCOMMIT=0语句,这语句会提交之前的事务。对于我们代码忘记写回滚,而直接返回结果的情况下,这是会出大问题的,也是我们目前唯一没有使用MYSQL_pconnect的原因。(计划近期找到没有写回滚语句的代码,修复,继续使用mysql_pconnect)

其实还有,我们php-fpm使用了APC来缓存php file,以及 变量数据等,这些也是有优化的地方(如果有时间的话,则待续)。

回过头来再理解下文章开头那位同学给的解决办法,我仍不能从他给的理由中,理解长连接的缺点,哪怕是解决了TIME_WAIT的问题,但每次创建TCP socket ,连接到服务器时三次握手,关闭TCP socket时的四次握手 这些也是开销。当然,缩短2MSL的时间,也是更好利用服务器资源的一个好方法。

最后,我们调整优化的服务器架构图如下:

好像有点偏离这篇文章的标题了,其实我更想说我不能理解为啥nginx跟php-fpm给的默认配置中,都是TCP socket通讯的,为啥不默认给unix domain socket的默认配置呢?如果说为了方便非同一台服务器时的情况,但给的默认IP也是回环地址呀。
而且,nginx给默认配置中,对于uri请求中的php文件的处理,匹配规则还是老的,之前发生因为NGINX与PHP的配置而导致的安全问题,虽然不是nginx的错,但nginx也可给出更严谨的范例,但仍没有。

值得欣慰的是,在UBUNTU 12.4中,nginx的默认配置有了很大的改进,不管是匹配uri的规则,还是nginx与php-fpm的交互方式:

01 #location ~ \.php$ {
02 #       fastcgi_split_path_info ^(.+\.php)(/.+)$;    //赞1
03 #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
04 #
05 #       # With php5-cgi alone:
06 #       fastcgi_pass 127.0.0.1:9000;    //赞3
07 #       # With php5-fpm:
08 #       fastcgi_pass unix:/var/run/php5-fpm.sock;    //赞3
09 #       fastcgi_index index.php;
10 #       include fastcgi_params;
11 #}

PS:末学只是个web程序员,这些只是末学学习研究如上知识的总结,理解上难免有错,各位请海涵。

<think>好的,我需要解释FastCGI如何使用socketLighttpd通信。首先,我得确认用户了解基本概念,比如FastCGI是什么,socket通信的类型。可能用户已经知道这些,但作为介绍的一部分,还是需要简要提及。 接下来,要区分Unix domain sockets和TCP sockets的区别。用户可能想知道为什么选择其中一种方式,以及各自的优缺点。需要解释它们的应用场景,比如Unix socket在本地通信效率更高,而TCP适用于远程或容器环境。 然后,具体配置步骤是关键。用户需要明确的步骤指导如何在Lighttpd中配置FastCGI使用socket。这里要确保语法正确,给出示例配置片段,并解释每个参数的作用,比如bin-path、socket、check-local等。需要注意路径和权限问题,这是实际配置中常见的坑点。 另外,权限设置是一个重要但容易被忽视的部分。需要提醒用户修改socket文件的权限,确保Lighttpd进程有访问权限,可能涉及chmod和chown命令。这部分需要详细说明,避免用户配置后出现权限错误。 性能调优部分,可以比较Unix socketTCP socket性能差异,帮助用户根据实际情况选择。同时,提到max-procs和bin-environment等参数的作用,让用户了解如何优化FastCGI进程的管理。 可能的问题排查也是必要的。比如socket文件不存在、权限问题、进程未启动等,给出对应的解决建议。这部分能帮助用户在遇到问题时快速定位和解决。 最后,总结使用socket的优势,强调安全性、性能和资源占用。这样用户能有一个全面的理解,知道为什么选择socket通信方式,以及如何正确配置和维护。 整个过程中,需要保持语言简洁明了,结构清晰,步骤详细。避免使用过于专业的术语,或者在必要时解释术语。同时,通过示例配置和命令,让用户可以直接参考应用,提升实用性。</think>### FastCGI 使用 Unix Socket Lighttpd 通信的原理配置 FastCGI 是一种高性能的 CGI(通用网关接口)协议,允许 Web 服务器(如 Lighttpd)外部程序(如 PHP/Python)高效通信。通过 **Unix Domain Socket**(文件系统 socket)而非 TCP 端口进行通信,可减少网络开销并提升安全性。以下是详细解析: --- #### 一、Unix Socket vs. TCP Socket | 类型 | Unix Domain Socket | TCP Socket | |-------------------|----------------------------------------|-------------------------| | **通信范围** | 同一台机器上的进程间通信 | 跨机器或本地进程通信 | | **性能** | 无网络协议栈开销,延迟更低 | 需要经过网络协议栈 | | **安全性** | 通过文件系统权限控制访问 | 依赖防火墙/IP白名单 | | **适用场景** | 本地服务(如 PHP-FPM Web 服务器) | 分布式服务或容器环境 | --- #### 二、Lighttpd 配置 FastCGI + Unix Socket ##### 1. **配置 Lighttpd 支持 FastCGI** 修改 Lighttpd 配置文件(通常为 `/etc/lighttpd/lighttpd.conf`),添加以下内容: ```nginx server.modules += ("mod_fastcgi") # 启用 FastCGI 模块 fastcgi.server = ( ".php" => (( "bin-path" => "/usr/bin/php-cgi", # PHP-FPM 的路径(如果使用 PHP-CGI) "socket" => "/var/run/php-fpm.sock", # 指定 Unix Socket 文件路径 "check-local" => "disable", # 禁止 Lighttpd 直接处理 PHP 文件 "max-procs" => 4, # 最大进程数 "bin-environment" => ( # 环境变量(可选) "PHP_FCGI_CHILDREN" => "4" ) )) ) ``` ##### 2. **配置 PHP-FPM 使用 Unix Socket** 编辑 PHP-FPM 配置文件(如 `/etc/php-fpm.d/www.conf`): ```ini [www] listen = /var/run/php-fpm.sock # Lighttpd 的 socket 路径一致 listen.owner = www-data # socket 文件所有者(需 Lighttpd 运行用户一致) listen.group = www-data listen.mode = 0660 # 文件权限 ``` --- #### 三、关键步骤权限设置 1. **创建 Socket 文件目录**: ```bash sudo mkdir -p /var/run/ sudo chown www-data:www-data /var/run/php-fpm.sock # 确保 Lighttpd 和 PHP-FPM 有权限访问 ``` 2. **重启服务**: ```bash sudo systemctl restart lighttpd php-fpm ``` 3. **验证 Socket 通信**: ```bash sudo lsof -U | grep php-fpm.sock # 查看 socket 是否被正确监听 ``` --- #### 四、性能调优建议 1. **选择 Unix Socket**: 本地服务优先使用 Unix Socket,避免 TCP 三次握手和网络延迟。 2. **调整进程数**: - `max-procs`:控制 Lighttpd 启动的 FastCGI 进程数量。 - `PHP_FCGI_CHILDREN`:控制每个 FastCGI 进程的子进程数(需根据服务器内存调整)。 3. **内核参数优化**(可选): ```bash # 提高 socket 队列长度 sysctl -w net.core.somaxconn=65535 ``` --- #### 五、常见问题排查 | 问题现象 | 可能原因 | 解决方案 | |--------------------------|--------------------------|-----------------------------------| | **502 Bad Gateway** | Socket 文件未创建 | 检查 PHP-FPM 是否运行,权限是否正确 | | **Permission denied** | Socket 文件权限错误 | 运行 `chmod 0660 /var/run/php-fpm.sock` | | **No input file specified** | `check-local` 未禁用 | 确认配置中 `check-local => "disable"` | --- #### 六、总结 - **优势**: Unix Socket 在本地通信中性能更高、资源占用更低,且通过文件系统权限实现安全隔离。 - **适用场景**: Lighttpd + PHP/Python 等本地服务的部署,尤其适合高并发场景。 - **扩展性**: 若需跨服务器通信(如容器化部署),可切换为 TCP Socket配置 `listen = 127.0.0.1:9000`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值