一般情况下我们搭建前端运行WEB环境时会采用Nginx比较多,使用Nginx作为Web服务器的时候,你或多或少都会遇到Nginx 502 bad gateway的错误,造成这种错误的原因有很多,下面我们来一一解析。
这样的错误提示问题502 Bad Gateway是指错误网关,无效网关;在互联网中表示一种网络错误。表现在WEB浏览器中给出的页面反馈。
含义:这通常并不意味着上游服务器已关闭(无响应网关/代理) ,而是上游服务器和网关/代理不同意的协议交换数据。鉴于互联网协议是相当清楚的,它往往意味着一个或两个机器已不正确或不完全编程。

502系列错误代码

  • HTTP Error 502 Bad Gateway HTTP 错误 502 网关错误
  • HTTP 502
  • 502 Service Temporarily Overloaded 502 服务暂时超载
  • Temporary Error (502) 临时错误 (502)
  • 502 Server Error: The server encountered a temporary error and could not - - complete your request 502 服务器错误:服务器遇到临时错误,无法完成您的请求
  • 502 Bad Gateway Nginx 502 网关坏 Nginx

5XX系列错误代码

  • 500 Internal Server ErrorWeb 服务器遇到遇到阻止其无法完成其任务(即客户端请求)的条件时,将显示此错误
  • 501 Not Implemented 服务器无法支持或识别请求方法。 它缺少处理请求的功能,因此它会响应此错误
  • 502 Bad Gateway 服务器之间发生了错误,充当代理或网关时,您的服务器在尝试处理请求时未收到上游服务器的正确响应
  • 503 Service Unavailable 由于正在进行维护或服务器当前过载而导致服务器无法处理请求的临时情况
  • 504 Gateway Timeout 服务器再次充当代理或网关时,没有及时从另一个服务器(例如DNS)获得响应,因此它无法处理请求
  • 505 HTTP Version Not Supported 当您的Web服务器不能或将不支持源自请求的HTTP协议版本时,将发生他的错误。 该错误通常包含服务器为什么不合作的描述

Nginx 502 Bad Gateway 错误的解决方案

出现nginx 502 bad gateway 问题,先从nginx端日志入手,分析排查原因。

1、代理缓冲区设置过小,使用了nginx反向代理的情况,绝大部分的前端转发代理都是这个原因,下面将详细阐述这方面

首先需要打开nginx错误日志。
编辑nginx.conf,默认路径在/usr/local/nginx/conf/nginx.conf,将错误日志输入到/usr/local/nginx/log/error_nginx.log,更改为info级别。

补充:

  • 错误日志级别:常见的错误日志级别有[debug | info | notice | warn | error | crit | alert | emerg],级别越高记录的信息越少。
  • 生产场景一般是 warn | error | crit 这三个级别之一
  • 注意:不要配置info等级较低的级别,会带来大量的磁盘I/O消耗,问题定位后,请调整日志级别至crit。

点击报错的业务功能,并查看nginx错误日志tail -50f /usr/local/nginx/log/error_nginx.log下面是我遇到的nginx报错,很明显是头部数据太大了 。如果header过大,超出了默认的1k,就会引发upstream sent too big header

【1】buffer工作原理

首先第一个概念是所有的这些proxy buffer参数是作用到每一个请求的。每一个请求会安按照参数的配置获得自己的buffer。proxy buffer不是global而是per request的。proxy_buffering是为了开启response buffering of the proxied server,开启后proxy_buffersproxy_busy_buffers_size参数才会起作用。

无论proxy_buffering是否开启,proxy_buffer_size(main buffer)都是工作的,proxy_buffer_size所设置的buffer_size的作用是用来存储upstream端response的header。

proxy_buffering开启的情况下,Nginx将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们被写满或者数据被读取完(EOF)。此时nginx开始向客户端传输数据,会同时传输这一整串buffer们。同时如果response的内容很大的话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。如果busy的buffer传输完了会从temp_file里面接着读数据,直到传输完毕。

一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户端的buffer数量的。

【2】buffer配置项

proxy_buffering

1
2
3
语法:proxy_buffering on|off
默认值:proxy_buffering on
上下文:http,server,location

作用:该指令开启从后端被代理服务器的响应body缓冲。

如果proxy_buffering开启,nginx假定被代理的后端服务器会以最快速度响应,并把内容保存在由指令 proxy_buffer_size 和 proxy_buffers 指定的缓冲区里边.
如果响应body无法放在内存里边,那么部分内容会被写到磁盘上。(大于proxy_buffers)
如果proxy_buffering被关闭了,那么响应body会按照获取body的多少立刻同步传送到客户端。nginx不尝试计算被代理服务器整个响应body的大小,nginx能从服务器接受的最大数据,是由指令 proxy_buffer_size指定的。
对于基于长轮询(long-polling)的Comet 应用来说,关闭 proxy_buffering 是重要的,不然异步响应将被缓存导致Comet无法工作。
但是无论proxy_buffering是否开启,proxy_buffer_size都是生效的。

proxy_buffers

1
2
3
语法:proxy_buffers  数量  size
默认值:proxy_buffers 256 8k
上下文:http,server,location

作用:设置存储被代理服务器响应的body所占用的buffer个数和每个buffer大小。

具体的意思是说,开辟256个长度为8k大小的read_buf用来存储body,当然不是连接建立初始化时就开辟256个,而是当当前buf不够存响应body时才会新申请一个,最多申请256个buf。

proxy_buffer_size

1
2
3
语法:proxy_buffer_size size
默认值:proxy_buffer_size 4k/8k
上下文:http,server,location

作用:Nginx使用该大小申请read_buf,即大小指定了 upstream header 最大长度,如果响应头超过了这个长度,Nginx会报upstream sent too big header错误,然后client收到的是502。

proxy_busy_buffer_size

1
2
语法:proxy_busy_buffer_size  size
上下文:http,server,location

作用:proxy_busy_buffers_size不是独立的空间,他是proxy_buffers和proxy_buffer_size的一部分。

nginx会在没有完全读完后端响应就开始向客户端传送数据,所以它会划出一部分busy状态的buffer来专门向客户端传送数据(建议为proxy_buffers中单个缓冲区的2倍),然后它继续从后端取数据。
proxy_busy_buffer_size参数用来设置处于busy状态的buffer有多大。

1)如果完整数据大小小于busy_buffer大小,当数据传输完成后,马上传给客户端;
2)如果完整数据大小不小于busy_buffer大小,则装满busy_buffer后,马上传给客户端;

proxy_temp_path

1
2
3
语法:proxy_temp_path  path [level1 level2 level3]
默认值:proxy_temp_path proxy_temp
上下文:http,server,location

作用:定义proxy的临时文件存在目录以及目录的层级。

proxy_max_temp_file_size

1
2
3
语法:proxy_max_temp_file_size size;
默认值:proxy_max_temp_file_size 1024m;
上下文:http, server, location

作用:设置临时文件的总大小

proxy_temp_file_wirte_size

1
2
3
语法:proxy_temp_file_write_size size;
默认值:proxy_temp_file_write_size 8k|16k;
上下文:http, server, location

作用:设置同时写入临时文件的数据量的总大小。通常设置为8k或者16k。

根据上面的说明.我在nginx.conf的header里添加了

【3】此问题解决方案

在nginx.conf转发的配置上增加,即location或server下面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
server_name *.test.com;

location / {
#添加这几行start
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 32 128k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
#添加这几行end
}
}

或者直接加载http模块配置下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
worker_processes  1;
events {
worker_connections 1024;
}
http {
#添加这几行start
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 32 128k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
#添加这几行end
server {
listen 80;
server_name localhost;

location / {
root /usr/local/openresty/nginx/html;
index index.html index.htm;
}
}
}

2、检查PHP基础设置

修改/www/server/php/80/etc/php-fpm.conf中的request_terminate_timeout = 100,把100改成5;
php执行超时,修改/usr/local/php/etc/php.inimax_execution_time为300;

3、FastCGI进程是否已经启动

nginx 502错误的含义是sock、端口没被监听造成的。我们先检查fastcgi是否在运行
ps aux | grep php
查看是否启动了php-fpm服务;

4、FastCGI worker进程数是否不够

fastcgi进程数不够用、php执行时间长、或者是php-cgi进程死掉也可能造成nginx的502错误,运行以下命令判断是否接近FastCGI进程,如果fastcgi进程数接近配置文件中设置的数值,表明worker进程数设置太少。

运行linux命令:

1
netstat -anpo | grep “php-cgi” | wc -l

判断是否接近FastCGI进程,接近配置文件中设置的数值,表明worker进程数设置太少;

5、FastCGI执行时间过长

PHP程序执行时间超过了Nginx等待时间,可以适当增加nginx.conf配置文件中FastCGI的timeout时间,根据实际情况调高以下参数值:

1
2
3
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;

6、FastCGI Buffer不够

nginx和apache一样,有前端缓冲限制,可以调整缓冲参数

1
2
fastcgi_buffer_size 32k;
fastcgi_buffers 8 32k;

如果你使用的是nginx的负载均衡Proxying,调整

1
2
proxy_buffer_size 16k;
proxy_buffers 4 16k;

7、FastCGI 缓冲区设置过小

首先查找nginx日志文件,目录/var/log/nginx,在日志中发现了如下错误:
[error] 15421#0: *16 upstream sent too big header while reading response header from upstream意思是nginx缓冲区bug造成。查阅了一下资料,大意是nginx缓冲区有一个bug造成的,我们网站的页面消耗占用缓冲区可能过大。参考老外写的修改办法增加了缓冲区容量大小设置,502问题彻底解决。后来系统管理员又对参数做了调整只保留了2个设置参数:client head buffer,fastcgi buffer size。网站页面占用缓冲区过大。增加缓冲区彻底解决了Nginx 502 Bad Gateway,方法如下:

1
2
3
4
5
6
http {
...
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
...
}

请根据服务器已经网站的情况自行增大上述两个配置项。

8、默认php-cgi的进程数设置过少

一台服务器上运行着nginx php(fpm) xcache,访问量日均 300W pv左右

最近经常会出现这样的情况: php页面打开很慢,cpu使用率突然降至很低,系统负载突然升至很高,查看网卡的流量,也会发现突然降到了很低。这种情况只持续数秒钟就恢复了

检查php-fpm的日志文件发现了一些线索:

1
Sep3008:32:23.289973[NOTICE] fpm_unix_init_main(), line 271: getrlimit(nofile): max:51200,cur:51200 Sep3008:32:23.290212[NOTICE] fpm_sockets_init_main(), line 371:using inherited socket fd=10,“127.0.0.1:9000″ Sep3008:32:23.290342[NOTICE] fpm_event_init_main(), line 109: libevent:using epoll Sep3008: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或者一个比较大的值:

在安装好使用过程中出现502问题,一般是因为默认php-cgi进程是5个,可能因为phpcgi进程不够用而造成502,需要修改/usr/local/php/etc/php-fpm.conf 将其中的max_children的值适当增加。也有可能是max_requests的值不够用。需要说明的是这连个配置项占用内存很大,请根据服务器配置进行设置。否则可能起到反效果。

9、其它原因

如果您上网时在您尝试访问的所有网站上都看这个问题,有两种可能

①你的ISP重大设备故障/过载

②有问题的内部互联网连接如您的防火墙无法正常运作。

在种情况下,只有您的ISP可以帮助您。在第二种情况下,你需要解决什么,那是阻止你进入互联网。

如果您只有在部分尝试访问的网站中出现此问题,那很可能是一个问题,即这些网站之一,其设备故障或超载。联系你网站的管理员。