若转载教程,请注明出自SW-X框架官方文档

1、502 Bad Gateway

官方解释:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
上面说到nginx收到了无法理解的响应,什么是无法理解的响应呢?

  1. nginx无法与php-fpm进行连接。
  2. nginx在连接php-fpm一段时间后发现与php-fpm的连接被断开。

那么什么时候会出现上面的情况呢?

  1. php-fpm没有启动,nginx无法将请求交给php-fpm
  2. php-fpm运行脚本超时,php-fpm终止了脚本的执行和执行脚本的Worker进程,nginx发现自己与php-fpm的连接断开

php-fpm没有启动

我们关闭php-fpm,刷新页面,发现返回502错误:
image.png
php-fpm请求超时
我们首先将php-fpm.conf中的max_terminate_request改成5s:

  1. request_terminate_timeout = 5

在php脚本中添加如下语句:

  1. sleep(20);

刷新页面,发现返回502错误:
image.png

2、其他502原因的检测

1、查看当前的PHP FastCGI进程数是否够用

  1. netstat -anpo | grep "php-cgi" | wc l

如果实际使用的【FastCGI进程数】接近预设的【FastCGI进程数】,那么,说明【FastCGI进程数】不够用,需要增大。

2、部分PHP程序的执行时间超过了Nginx的等待时间

可以适当增加nginx.conf配置文件中FastCGI的timeout时间。php.ini中memory_limit设低了会出错,修改了php.ini的memory_limit为64M,重启nginx,如果发现恢复了,那么就是PHP的内存不足的原因。

3、max-children和max-requests

主机上运行着nginx php(fpm) xcache的话,访问量日均 300W pv左右。如果是近期出现php页面打开很慢,cpu使用率突然降至很低,系统负载突然升至很高,查看网卡的流量,也会发现突然降到了很低这样的情况,而且这种情况只持续数秒钟就恢复,这时检查php-fpm的日志文件发现了一些线索:

  1. 1Sep 30 08:32:23.289973 \[NOTICE\] fpm\_unix\_init\_main(), line 271: getrlimit(nofile): max:51200 cur:51200
  2. 2Sep 30 08:32:23.290212 \[NOTICE\] fpm\_sockets\_init\_main(), line 371: using inherited socket fd=10 127.0.0.1:9000
  3. 3Sep 30 08:32:23.290342 \[NOTICE\] fpm\_event\_init\_main(), line 109: libevent: using epoll
  4. 4Sep 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,在大流量下,每个children到达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,就能恢复了。

4、增加缓冲区容量大小

将nginx的error log打开,发现【pstream sent too big header while reading response header from upstream】这样的错误提示。大概意思是nginx缓冲区有一个bug造成的,网站的页面消耗占用缓冲区可能过大。
参考国外系统管理员写的修改办法,增加了缓冲区容量大小设置,502问题彻底解决。后来系统管理员又对参数做了调整只保留了2个设置参数:client head buffer,fastcgi buffer size。

5、PHP脚本的最大执行时间

  1. max_execution_time //php.ini
  2. request_terminate_timeout //php.ini

这两项都是用来配置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秒

  1. request_terminate_timeout = 600

3、504 Bad Gateway timeout

504 即 nginx 超过了自己设置的超时时间,不等待 php-fpm 的返回结果,直接给客户端返回 504 错误。但是此时 php-fpm 依然还在处理请求(在没有超出自己的超时时间的情况下).
这里有三个相关的配置:

  1. 3504 Bad Gateway timeout
  2. 504 nginx 超过了自己设置的超时时间,不等待 php-fpm 的返回结果,直接给客户端返回 504 错误。但是此时 php-fpm 依然还在处理请求(在没有超出自己的超时时间的情况下).
  3. 这里有三个相关的配置:

网关超时,客户端所发出的请求没有到达网关,在限定时间内没有得到php-fpm,或者完成php-fpm的传输数据的工作而超时 。
比方说:即nginx的worker去php-fpm进程池去处理,但是没有fpm进程可以使用了,等啊等,还是没有,返回504。

场景

nginx的fastcgi模块有一个fastcgi_read_timeout配置,它表示从FastCGI server获取数据的超时时间。
如果超过这个配置客户端就是收到504的响应。
比如执行了一段非常耗时的查询语句,nginx的相关fastcgi等待配置超时后,就会返回504,但是php-fpm还在运行。

解决办法网关超时,客户端所发出的请求没有到达网关,在限定时间内没有得到php-fpm,或者完成php-fpm的传输数据的工作而超时 。
比方说:即nginx的worker去php-fpm进程池去处理,但是没有fpm进程可以使用了,等啊等,还是没有,返回504。

场景

nginx的fastcgi模块有一个fastcgi_read_timeout配置,它表示从FastCGI server获取数据的超时时间。
如果超过这个配置客户端就是收到504的响应。
比如执行了一段非常耗时的查询语句,nginx的相关fastcgi等待配置超时后,就会返回504,但是php-fpm还在运行。

解决办法

  1. location ~ \.php$ {
  2. fastcgi_connect_timeout 180;//优化点
  3. fastcgi_read_timeout 600;//优化点
  4. fastcgi_send_timeout 600;//优化点
  5. fastcgi\_pass unix:/tmp/php-fpm.sock;
  6. fastcgi\_index index.php;
  7. include fastcgi.conf;
  8. }

调高上面标红的3个值后,主要是read和send两项(默认Nginx超时为60),完美地解决了504错误。
并且可以配置在http,server级别,也可以配置在location级别。

  1. factcgi_connect_{read|send|timeout}是对fastcgi_pass生效
  2. proxy_connect_{read|send|timeout|是对proxy_pass生效