nginx+php-fpm.sock时504,502错误解决办法


环境:

CentOS 7.1 x64

nginx-1.8.0

php-5.6.17

nginx和php通信采用的是unix socket机制

小记:
http://nginx.org/en/docs/stream/ngx_stream_core_module.html  nginx-1.9.0开始支持tcp的反向代理,编译时需要加上--with-stream参数



504

出现错误的前因

在phpMyAdmin中执行了一段非常耗时的查询语句,不一会功夫,phpMyAdmin就报如下错误


nginx日志

2016/04/02 22:28:56 [error] 15308#0: *53 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 192.168.130.1, server: ssl.example.com, request: "POST /phpMyAdmin/import.php HTTP/1.1", upstream: "fastcgi://unix:/dev/shm/php-fpm.sock", host: "192.168.130.254", referrer: "https://192.168.130.254/phpMyAdmin/db_sql.php?db=isfdb&token=b9cf017794df498e0cb52518b8021c82"

2016/04/02 22:33:00 [error] 15305#0: *71 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 192.168.130.1, server: ssl.example.com, request: "GET /phpMyAdmin/

注意:重启nginx无效),但只治得了一时,于时开始查找解决方案

解决办法

location ~ \.php$ {
    
  fastcgi_connect_timeout 
   
    
  fastcgi_read_timeout  
     
    
  fastcgi_send_timeout  

     
}

调高上面标红的3个值后,主要是read和send两项(默认Nginx超时为60),完美地解决了504错误。

并且可以配置在http,server级别,也可以配置在location级别。

factcgi_connect_{read|send|timeout}是对fastcgi_pass生效

proxy_connect_{read|send|timeout|是对proxy_pass生效

502

的确,504是解决了,但运行一段时间后,又报了502错误


nginx日志

2016/04/02 23:24:55
[error] 18748#0: *35 recv() failed (104:
Connection reset by peer) while reading response header
from upstream, client: 192.168.130.1, server: ssl.example.com,
request: "POST /phpMyAdmin/import.php HTTP/1.1", upstream:
"fastcgi://unix:/dev/shm/php-fpm.sock:", host: "192.168.130.254",
referrer:
"https://192.168.130.254/phpMyAdmin/db_sql.php?db=isfdb&token=231148330c40cfa09b03d52ccf49f38a"


php-fpm日志

[02-Apr-2016
23:24:55] WARNING: [pool www] child 18822, script
'/usr/local/nginx/html/phpMyAdmin/import.php' (request: "POST
/phpMyAdmin/import.php") execution timed
out (340.677871 sec), terminating
[02-Apr-2016
23:24:55] WARNING: [pool www] child 18822 exited on signal 15
(SIGTERM) after 396.757450 seconds from start

[02-Apr-2016
23:24:55] NOTICE: [pool www] child 19164 started

从日志上可以看到, 23:24:55的时,php-fpm的子进程18822因为等待了340.677871秒后被强行终止了并重新生成了一个新的子进程19164

但因为自动生成了新子进程,php网页还是可以正常访问的,只是该查询任务被终止了。


解决办法

max_execution_time值

php-fpm.conf中的request_terminate_timeout值


还会终止执行脚本的Worker进程。

如上,php-fpm child 18822被terminate后重新生成了新的Worker进程19164,所以nginx发现与自己通信的连接断了,就自然会返回502错误给客户端。客户端需再次发起请求重新建立新的连接,表象是刷新下浏览器即重新发起请求

所以只需将这两项的值适当调大,让PHP脚本不会因为执行时间长而被终止从而与nginx激活连接丢失。


不想改全局的php.ini,只改php-fpm的配置就可以了。这里暂且调到600秒

request_terminate_timeout = 600




补充:

nginx也要注意upstream模块中max_fail和fail_timeout。有时nginx与后端服务器(Tomcat、FastCGI)的通信只是偶然断掉,但max_fail设置太小,那么在接下来的fail_timeout时间内,nginx都会认为后端服务器无响应,都会返回502错误。

所以可以将max_fail调大一些,将fail_timeout调小一些