PHP错误:upstream timed out (60: Operation timed out) while reading response header from upstream
PHP 提示错误:
==> /usr/local/nginx/logs/error.log <==
2017/12/27 08:36:08 [error] 20443#0: *139 upstream timed out (60: Operation timed out) while reading response header from upstream, client: 127.0.0.1, server: 127.0.0.1, request: "GET /api/header.php?url=http://bjetc.cn&resheaders=1 HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost:8084"
==> /usr/local/nginx/logs/host.access.log <==
2017-12-27T08:36:08+08:00 127.0.0.1 - "GET /50x.html?-" 504 150.000 537 "-" "curl/7.54.0" "-"
原因分析
环境:Mac OS + Nginx + php-fpm
从提示信息看,是读取流文件,如读取文件、网络连接(Linux中也是流文件读取)超时,服务器返回504
504 状态码含义:关口过载,服务器使用另一个关口或服务来响应用户,等待时间设定值较长
502状态码含义:服务器暂时不可用,有时是为了防止发生系统过载
更多状态码请见米扑博客:HTTP返回状态值详解
一般的原因是读取的文件太大、不存在,或网络连接超时、网站无法访问等。
Nginx 504 Gateway Time-out的含义是所请求的网关没有请求到,简单来说就是没有请求到可以执行的PHP-CGI
Nginx 502 Bad Gateway的含义是请求的PHP-CGI已经执行,但是由于某种原因(一般是读取资源的问题)没有执行完毕而导致PHP-CGI进程终止
一般来说Nginx 502 Bad Gateway和php-fpm.conf的设置有关,而Nginx 504 Gateway Time-out则是与nginx.conf的设置有关
解决方法
1. 开启慢日志监控
1)在 php-fpm.conf 开启慢日志(默认是关闭的)
vim /usr/local/php/etc/php-fpm.conf
删除分号,取消注释,修改后如下:
slowlog = log/$pool.log.slow ;request_slowlog_timeout = 0 request_slowlog_timeout = 5
2)创建日志文件夹目录 log ,用于保存 $pool.log.slow
其中 pool 一般为 www,完整日志文件名为 /usr/local/php5/log/www.log.slow
mkdir /usr/local/php/log
说明:
1)slowlog 用于保存慢日志,一般配合 request_slowlog_timeout 一起使用
2)request_slowlog_timeout 表示请求处理慢于多少时间的为慢请求,request_slowlog_timeout = 0表示关闭慢日志
例如 request_slowlog_timeout = 5 表示请求处理时间慢于 5秒的为慢请求,写入慢日志文件
3)重启 php-fpm 使其生效
/etc/init.d/php-fpm restart
4)查看慢日志
tail -f /usr/local/php5/log/*.log.slow
日志记录如下:
$ tail -f /usr/local/php5/log/*.log.slow
[27-Dec-2017 10:03:07] [pool www] pid 24098
script_filename = /Users/homer/workspace/mimvp_site/api/header.php
[0x000000010643d1d8] flock() /Users/homer/workspace/mimvp_site/api/header.php:876
[0x000000010643cf50] lock() /Users/homer/workspace/mimvp_site/api/header.php:91
[27-Dec-2017 10:22:00] [pool www] pid 31362
script_filename = /Users/homer/workspace/mimvp_site/api/header.php
[0x0000000106ac6820] curl_exec() /Users/homer/workspace/mimvp_site/api/header.php:684
[0x0000000106ac60d0] get_siteurl_curlinfo() /Users/homer/workspace/mimvp_site/api/header.php:258
[27-Dec-2017 10:22:55] [pool www] pid 31359
script_filename = /Users/homer/workspace/mimvp_site/api/header.php
[0x0000000106ac7fc0] curl_exec() /opt/php-selenium/vendor/facebook/webdriver/lib/remote/HttpCommandExecutor.php:225
[0x0000000106ac6e08] execute() /opt/php-selenium/vendor/facebook/webdriver/lib/remote/RemoteWebDriver.php:491
[0x0000000106ac6bb8] execute() /opt/php-selenium/vendor/facebook/webdriver/lib/remote/RemoteWebDriver.php:171
[0x0000000106ac6960] get() /Users/homer/workspace/mimvp_site/api/header.php:724
[0x0000000106ac5f50] get_siteurl_selenium() /Users/homer/workspace/mimvp_site/api/header.php:285
根据慢日志,查看代码 flock() /Users/homer/workspace/mimvp_site/api/header.php:876
return flock($this->fp, LOCK_EX); // 独占锁定
请求超时的原因在于文件锁,锁定后未及时释放,改进方案就是try - catch 捕获异常,释放锁
根据慢日志,查看代码 curl_exec() /Users/homer/workspace/mimvp_site/api/header.php:684
原因是 php curl 执行超时,selenium + webdriver 的 curl_exec 也是curl超时,需设置curl超时参数
$ch = curl_init(); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // HTTP 头中的 "Location: "重定向 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 字符串返回 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_HEADER, 1); // 0表示不输出Header,1表示输出 curl_setopt($ch, CURLOPT_NOBODY, 0); // 0表示不输出Body,1表示输出 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 尝试连接时等待的秒数。设置为0,则无限等待 curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 允许 cURL 函数执行的最长秒数 curl_setopt($ch, CURLOPT_URL, $url); $output = curl_exec($ch); curl_close($ch);
2. 设置超时和缓存大小
nginx 的超时和缓存大小,也会影响请求的响应速度
修改nginx配置文件 nginx.conf
vim /usr/local/nginx/conf/nginx.conf
添加配置如下:
http { include mime.types; default_type application/octet-stream; charset utf-8; log_format main '$time_iso8601 $remote_addr - "$request_method $uri?$args" ' '$status $request_time $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; #keepalive_timeout 0; keepalive_timeout 65; server_tokens off; fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 256k; fastcgi_buffers 8 256k; fastcgi_busy_buffers_size 512k; fastcgi_temp_file_write_size 256k; fastcgi_intercept_errors on; proxy_connect_timeout 300; proxy_read_timeout 300; proxy_send_timeout 300; proxy_buffer_size 256k; proxy_buffers 8 256k; proxy_busy_buffers_size 512k; proxy_temp_file_write_size 256k; gzip on; gzip_min_length 1k; gzip_buffers 4 256k; gzip_proxied off; gzip_http_version 1.1; gzip_comp_level 4; gzip_types text/plain text/xml text/css text/javascript application/json application/x-javascript application/xml application/xml+css; gzip_vary on; client_header_buffer_size 128k; large_client_header_buffers 8 256k; client_body_buffer_size 16m; client_max_body_size 320m; client_header_timeout 5; client_body_timeout 10;
如上,重点看 fastcgi 和 proxy 配置,包含超时和缓存大小
3. 优化配置文件 php-fpm.conf
nginx 转发请求给 php-fpm 处理,再转给 php-cgi 处理,因此瓶颈问题一般出在 php-fpm
php-fpm.conf有两个至关重要的参数,一个是 max_children,另一个是 request_terminate_timeout
max_children
这个值又是怎么计算出来的呢?这个值原则上是越大越好,php-cgi的进程多了就会处理的很快,排队的请求就会很少。
设置 max_children 需要根据服务器的性能进行设定,一般来说一台服务器正常情况下每一个php-cgi所耗费的内存在20M左右,因此内存1GB 则 max_children 设置成40个,20M*40=800M也就是说在峰值的时候所有PHP-CGI所耗内存在800M以内,低于有效内存1GB。而如果”max_children”设置的较小,比如5-10个,那么php-cgi就会“很累”,处理速度也很慢,等待的时间也较长。如果长时间没有得到处理的请求就会出现504 Gateway Time-out这个错误,而正在处理的很累的那几个php-cgi如果遇到了问题就会出现502 Bad gateway这个错误。
request_terminate_timeout
如果你的服务器性能足够好,且宽带资源足够充足,PHP脚本没有系循环或BUG的话你可以直接将”request_terminate_timeout” 设置成0
0 的含义是让PHP-CGI一直执行下去而没有时间限制。而如果做不到这一点,也就是说你的PHP-CGI可能出现某个BUG,或者你的宽带不够充足或者其他的原因导致你的PHP-CGI能够假死那么就建议你给”request_terminate_timeout”赋一个值,这个值可以 根据你服务器的性能进行设定。一般来说性能越好你可以设置越高,20-30分钟都可以。由于我的服务器PHP脚本需要长时间运行,有的可能会超过10 分钟因此我设置了1200秒(20分钟),这样不会导致PHP-CGI死掉而出现502 Bad gateway这个错误。如果把request_terminate_timeout由之前的0s改为60s,这样php-cgi进程处理脚本的超时时间就是60秒,可以防止进程都被挂起,提高利用效率,推荐设置为 60s
vim /usr/local/php/etc/php-fpm.conf
修改配置如下:
; The timeout for serving a single request after which the worker process will ; be killed. This option should be used when the 'max_execution_time' ini option ; does not stop script execution for some reason. A value of '0' means 'off'. ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) ; Default Value: 0 ;request_terminate_timeout = 0 request_terminate_timeout = 60s
和
;syslog.ident = php-fpm ; static - a fixed number (pm.max_children) of child processes; ; pm.max_children - the maximum number of children that can ; pm.start_servers - the number of children created on startup. ; pm.min_spare_servers - the minimum number of children in 'idle' ; pm.max_spare_servers - the maximum number of children in 'idle' ; pm.max_children - the maximum number of children that ; pm.process_idle_timeout - The number of seconds after which pm = dynamic ; The number of child processes to be created when pm is set to 'static' and the ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. ; forget to tweak pm.* to fit your needs. ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' ;pm.max_children = 5 pm.max_children = 20 ;pm.start_servers = 2 pm.start_servers = 8 ;pm.min_spare_servers = 1 pm.min_spare_servers = 6 ;pm.max_spare_servers = 3 pm.max_spare_servers = 10 ;pm.process_idle_timeout = 10s; ;pm.max_requests = 500
参考推荐:
PHP错误:Allowed memory size of 268435456 bytes exhausted (tried to allocate 87 bytes)
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2018-06-02 05:21:03
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!