环境:

CentOS 7.1 x64

nginx-1.8.0

php-5.6.17

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

504

出现错误的前因

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

 

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/ HTTP/1.1″, upstream: “fastcgi://unix:/dev/shm/php-fpm.sock”, host: “192.168.130.254”

此里所有同php解析的动态内容全部无法打开,想临时解决,重启php-fpm即可(注意:重启nginx无效),但只治得了一时,于时开始查找解决方案

解决办法

location ~ \.php$ {

        fastcgi_connect_timeout      180;

        fastcgi_read_timeout         600;

        fastcgi_send_timeout         600;

fastcgi_pass unix:/tmp/php-fpm.sock;

fastcgi_index index.php;

include fastcgi.conf;

}

调高上面标红的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网页还是可以正常访问的,只是该查询任务被终止了。

解决办法

php.ini中的max_execution_time值 php-fpm.conf中的request_terminate_timeout值
这两项都是用来配置PHP脚本的最大执行时间。超时时php-fpm会终止脚本的执行,同时还会终止执行脚本的Worker进程。 如上,php-fpm child 18822被terminate后重新生成了新的Worker进程19164,所以nginx发现与自己通信的连接断了,就自然会返回502错误给客户端。客户端需再次发起请求重新建立新的连接,表象是刷新下浏览器即重新发起请求

所以只需将这两项的值适当调大,让PHP脚本不会因为执行时间长而被终止从而与nginx激活连接丢失。
request_terminate_timeout优先级高于max_execution_time,不想改全局的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调小一些

 

via http://ju.outofmemory.cn/entry/251073

- EOF -