首先,这里讲的站群服务器环境(lnmp)是指 linux + nginx + php(php-cgi + php-fpm)+ mysql 。
502 Bad Gateway 是 lnmp 下出现得最频繁的问题,其原因也有很多,以下是我收集的问题原因及其解决方法。
1. php 程序死亡
此原因的问题表现为:每次动态(php)请求都出现 502 错误
解决方法:启动 php 即可 “service php-fpm start ”,或者 “php 安装路径/php/sbin/php-fpm start”
2. php-cgi 程序数不足
此原因的问题表现为:动态请求有时出现 502 错误,一般没问题,这是并发高时 php-cgi 程序数不够用的表现
解决方法:修改 php-fpm 配置 php-fpm.conf,将
3. php-cgi 程序超时
此原因的问题表现为:php 程序执行一段时间后出现 502 错误,这种情况可能是 php 程式没有加 set_time_limit(0),也可能是被 php-fpm 的设定限定了执行时间,下面讨论第二中情况
解决方法:修改 php-fpm 配置 php-fpm.conf,将
4. 磁碟空间不足
此原因较少,问题表现为:502 错误或者无法连线到站群服务器,无法连线到站群服务器时 nginx 也死了
这种情况的判断:启动 php-fpm 或者 nginx 的时间较长,但最终启动失败,这大概就是磁碟空间不足了,然后可以用命令检视磁碟占用状况:df -lh ,如果根目录 “/” 对应的磁碟使用率为 100%,那么需要清理磁碟空间
解决方法:删除过大的日志档案,关闭部分服务元件的日志。一般需要检查 /var/log 目录下的日志档案,检查 nginx 、 php 的日志,检查 mysql 的日志。如果以上目录没有问题,则需一个一个的检查其他目录(优先检查 /usr 目录),删除过大的档案。
Nginx 502 Bad Gateway 的含义是请求的 PHP-CGI 已经执行,但是由于某种原因(一般是读取资源的问题)没有执行完毕而导致 PHP-CGI 程序终止。
Nginx 504 Gateway Time-out 的含义是所请求的闸道器没有请求到,简单来说就是没有请求到可以执行的 PHP-CGI 。
解决这两个问题其实是需要综合思考的,一般来说 Nginx 502 Bad Gateway 和 php-fpm.conf 的设定有关,而 Nginx 504 Gateway Time-out 则是与 nginx.conf 的设定有关。
而正确的设定需要考虑站群服务器自身的效能和访客的数量等多重因素。
以我目前的站群服务器为例子 CPU 是奔四 1.5G 的,内存 1GB,CENTOS 的系统,访客大概是 50 人左右同时线上。
但是线上的人大都需要请求 PHP-CGI 进行大量的资讯处理,因此我将 nginx.conf 设定为:
fastcgi_connect_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
fastcgi_buffer_size 128k;
fastcgi_buffers 8 128k;#8 128
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
这里最主要的设定是前三条,即
fastcgi_connect_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
这里规定了 PHP-CGI 的连线、传送和读取的时间,300 秒足够用了,因此我的站群服务器很少出现 504 Gateway Time-out 这个错误。最关键的是 php-fpm.conf 的设定,这个会直接导致 502 Bad Gateway 和 504 Gateway Time-out 。
下面我们来仔细分析一下 php-fpm.conf 几个重要的引数:
php-fpm.conf 有两个至关重要的引数,一个是”max_children”, 另一个是”request_terminate_timeout”
我的两个设定的值一个是”40″,一个是”900″,但是这个值不是通用的,而是需要自己计算的。
计算的方式如下:
如果你的站群服务器效能足够好,且宽频资源足够充足,PHP 指令码没有系回圈或 BUG 的话你可以直接将”request_terminate_timeout” 设定成 0s 。 0s 的含义是让 PHP-CGI 一直执行下去而没有时间限制。而如果你做不到这一点,也就是说你的 PHP-CGI 可能出现某个 BUG,或者你的宽频不够充足或者其他的原因导致你的 PHP-CGI 能够假死那么就建议你给”request_terminate_timeout” 赋一个值,这个值可以根据你站群服务器的效能进行设定。一般来说效能越好你可以设定越高,20 分钟-30 分钟都可以。由于我的站群服务器 PHP 指令码需要长时间执行,有的可能会超过 10 分钟因此我设定了 900 秒,这样不会导致 PHP-CGI 死掉而出现 502 Bad gateway 这个错误。
而”max_children” 这个值又是怎么计算出来的呢?这个值原则上是越大越好,php-cgi 的程序多了就会处理的很快,排队的请求就会很少。设定”max_children” 也需要根据站群服务器的效能进行设定,一般来说一台站群服务器正常情况下每一个 php-cgi 所耗费的内存在 20M 左右,因此我的”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 这个错误。
一些执行在 Nginx 上的网站有时候会出现 “502 Bad Gateway” 错误,有些时候甚至频繁的出现。以下是从 Google 搜集整理的一些 Nginx 502 错误的排查方法,供参考:
Nginx 502 错误的原因比较多,是因为在代理模式下后端站群服务器出现问题引起的。这些错误一般都不是 nginx 本身的问题,一定要从后端找原因!但 nginx 把这些出错都揽在自己身上了,著实让 nginx 的推广者备受置疑,毕竟从字眼上理解,bad gateway?不就是 bad nginx 吗?让不了解的人看到,会直接把责任推在 nginx 身上,希望 nginx 下一个版本会把出错提示写稍微友好一些,至少不会是现在简单的一句 502 Bad Gateway,另外还不忘附上自己的大名。
Nginx 502 的触发条件
502 错误最通常的出现情况就是后端 WordPress 主机当机。在 upstream 配置里有这么一项配置:proxy_next_upstream,这个配置指定了 nginx 在从一个后端 WordPress 主机取资料遇到何种错误时会转到下一个后端 WordPress 主机,里头写上的就是会出现 502 的所有情况拉,预设是 error timeout 。 error 就是当机、断线之类的,timeout 就是读取堵塞超时,比较容易理解。我一般是全写上的:
proxy_next_upstream error timeout invalid_header http_500 http_503;
不过现在可能我要去掉 http_500 这一项了,http_500 指定后端返回 500 错误时会转一个 WordPress 主机,后端的 jsp 出错的话,本来会列印一堆 stacktrace 的错误资讯,现在被 502 取代了。但公司的程式设计师可不这么认为,他们认定是 nginx 出现了错误,我实在没空跟他们解释 502 的原理 了……
503 错误就可以保留,因为后端通常是 apache resin,如果 apache 宕机就是 error,但 resin 宕机,仅仅是 503,所以还是有必要保留的。
解决办法
遇到 502 问题,可以优先考虑按照以下两个步骤去解决。
1 、检视当前的 PHP FastCGI 程序数是否够用:
netstat -anpo | grep “php-cgi” | wc -l
如果实际使用的 “FastCGI 程序数” 接近预设的 “FastCGI 程序数”,那么,说明 “FastCGI 程序数” 不够用,需要增大。
2 、部分 PHP 程式的执行时间超过了 Nginx 的等待时间,可以适当增加 nginx.conf 配置档案中 FastCGI 的 timeout 时间,例如:
……http{……fastcgi_connect_timeout 300;fastcgi_send_timeout 300;fastcgi_read_timeout 300;……}……
php.ini 中 memory_limit 设低了会出错,修改了 php.ini 的 memory_limit 为 64M,重启 nginx,发现好了,原来是 PHP 的内存不足了。
如果这样修改了还解决不了问题,可以参考下面这些方案:
一、 max-children 和 max-requests
一台站群服务器上执行著 nginx php(fpm) xcache,访问量日均 300W pv 左右
最近经常会出现这样的情况: php 页面开启很慢,cpu 使用率突然降至很低,系统负载突然升至很高,检视网络卡的流量,也会发现突然降到了很低。这种情况只持续数秒钟就恢复了
检查 php-fpm 的日志档案发现了一些线索
Sep 30 08:32:23.289973 [NOTICE] fpm_unix_init_main(), line 271: getrlimit(nofile): max:51200, cur:51200Sep 30 08:32:23.290212 [NOTICE] fpm_sockets_init_main(), line 371: using inherited socket fd=10, “127.0.0.1:9000″Sep 30 08:32:23.290342 [NOTICE] fpm_event_init_main(), line 109: libevent: using epollSep 30 08:32:23.296426 [NOTICE] fpm_init(), line 47: fpm is running, pid 30587
在这几句的前面,是 1000 多行的关闭 children 和开启 children 的日志
原来,php-fpm 有一个引数 max_requests,该引数指明了,每个 children 最多处理多少个请求后便会被关闭,预设的设定是 500 。因为 php 是把请求轮询给每个 children,在大流量下,每个 childre 到达 max_requests 所用的时间都差不多,这样就造成所有的 children 基本上在同一时间 被关闭。
在这期间,nginx 无法将 php 档案转交给 php-fpm 处理,所以 cpu 会降至很低 (不用处理 php,更不用执行 sql),而负载会升至很高 (关闭和开启 children 、 nginx 等待 php-fpm),网络卡流量也降至很低 (nginx 无法生成资料传输给客户端)
解决问题很简单,增加 children 的数量,并且将 max_requests 设定未 0 或者一个比较大的值:
开启 /usr/local/php/etc/php-fpm.conf
调大以下两个引数 (根据站群服务器实际情况,过大也不行)
然后重启 php-fpm 。
二、增加缓冲区容量大小
将 nginx 的 error log 开启,发现 “pstream sent too big header while reading response header from upstream” 这样的错误提示。查阅了一下资料,大意是 nginx 缓冲区有一个 bug 造成的, 我们网站的页面消耗占用缓冲区可能过大。参考老外写的修 改办法增加了缓冲区容量大小设定,502 问题彻底解决。后来系统管理员又对引数做了调整只保留了 2 个设定引数:client head buffer,fastcgi buffer size 。
三、 request_terminate_timeout
如果主要是在一些 post 或者资料库操作的时候出现 502 这种情况,而不是在静态页面操作中常见,那么可以检视一下 php-fpm.conf 设定中的一项:
request_terminate_timeout
这个值是 max_execution_time,就是 fast-cgi 的执行指令码时间。
0s
0s 为关闭,就是无限执行下去。(当时装的时候没仔细看就改了一个数字)
发现,问题解决了,执行很长时间也不会出错了。
优化 fastcgi 中,还可以改改这个值 5s 看看效果。
php-cgi 程序数不够用、 php 执行时间长、或者是 php-cgi 程序死掉,都会出现 502 错误。
原文连结:http://www.centoscn.com/CentosBug/softbug/2017/0228/8555.html