# 一、简介
一个普通的http
请求处理流程,如上图所示:
A -> client
端发起请求给nginx
B -> nginx
处理后,将请求转发到uwsgi
,并等待结果
C -> uwsgi
处理完请求后,返回数据给nginx
D -> nginx
将处理结果返回给客户端
每个阶段都会有一个预设的超时时间,由于网络、机器负载、代码异常等等各种原因,如果某个阶段没有在预期的时间内正常返回,就会导致这次请求异常,进而产生不同的状态码。
# 二、504 错误
504
主要是针对B
、C
阶段。一般nginx
配置中会有:
location / {
...
uwsgi_connect_timeout 6s;
uwsgi_send_timeout 6s;
uwsgi_read_timeout 10s;
uwsgi_buffering on;
uwsgi_buffers 80 16k;
...
}
2
3
4
5
6
7
8
9
这个代表nginx
与上游服务器uwsgi
通信的超时时间,也就是说,如果在这个时间内,uwsgi
没有响应,则认为这次请求超时,返回504
状态码。
具体的日志如下:access_log
[16/May/2016:22:11:38 +0800] 10.4.31.56 201605162211280100040310561523 15231401463407888908 10.*.*.* 127.0.0.1:8500 "GET /api/media_article_list/?count=10&source_type=0&status=all&from_time=0&item_id=0&flag=2&_=1463407896337 HTTP/1.1" 504 **.***.com **.**.**.39, **.**.**.60 10.000 10.000 "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36" ...
error_log
2016/05/16 22:11:38 [error] 90674#0: *947302032 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 10.6.19.81, server: **.***.com, request: "GET /api/media_article_list/?count=10&source_type=0&status=all&from_time=0&item_id=0&flag=2&_=1463407896337 HTTP/1.1", upstream: "http://127.0.0.1:8500/**/**/api/media_article_list/?count=10&source_type=0&status=all&from_time=0&item_id=0&flag=2&_=1463407896337", host: "mp.toutiao.com", referrer: "https://**.***.com/articles/?source_type=0"
error_log中upstream timed out (110: Connection timed out) while reading response header from upstream,
2
3
4
5
意思是说,在规定的时间内,没有从header
中拿到数据,即uwsgi
没有返回任何数据。
Nginx 504 Gateway Time-out
的含义是所请求的网关没有请求到,简单来说就是没有请求到可以执行的PHP-CGI
。Nginx 504 Gateway Time-out
则是与nginx.conf
的设置有关。504 Gateway Time-out
问题常见于使用nginx
作为web server
的服务器的网站。
一般看来, 这种情况可能是由于nginx
默认的fastcgi
进程响应的缓冲区太小造成的, 这将导致fastcgi
进程被挂起, 如果你的fastcgi
服务对这个挂起处理的不好, 那么最后就极有可能导致504 Gateway Time-out
现在的网站, 尤其某些论坛有大量的回复和很多内容的, 一个页面甚至有几百K
默认的fastcgi
进程响应的缓冲区是8K
, 我们可以设置大点在nginx.conf
里, 加入:
fastcgi_buffers 8 128k #这表示设置fastcgi缓冲区为8×128k,当然如果您在进行某一项即时的操作, 可能需要nginx的超时参数调大点, 例如设置成60秒:
send_timeout 60; #只是调整了上面这两个参数, 结果可能就是没有再显示那个超时!
#解决办法:调整nginx.conf的相关设置:
fastcgi_connect_timeout 600;
fastcgi_send_timeout 600;
fastcgi_read_timeout 600;
fastcgi_buffer_size 256k;
fastcgi_buffers 16 256k;
fastcgi_busy_buffers_size 512k;
fastcgi_temp_file_write_size 512k;
2
3
4
5
6
7
8
9
10
11
12
# 三、502 错误
502
主要针对B
、C
阶段。产生502
的时候,对应的error_log
中的内容会有好几种:
access_log
[16/May/2016:16:39:49 +0800] 10.4.31.56 201605161639490100040310562612 2612221463387989972 10.6.19.81 127.0.0.1:88 "GET /articles/?source_type=0 HTTP/1.1" 503 **.***.com **.**.**.4, **.**.**.160 0.000 0.000 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36" "uuid=\x22w:546d345b86ca443eb44bd9bb1120e821\x22; tt_webid=15660522398; lasttag=news_culture; sessionid=f172028cc8310ba7f503adb5957eb3ea; sid_tt=f172028cc8310ba7f503adb5957eb3ea; _ga=GA1.2.354066248.1463056713; _gat=1"
error_log
2016/05/16 16:39:49 [error] 90693#0: *944980723 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 10.6.19.80, server: **.***.com, request: "GET /articles/ HTTP/1.1", upstream: "http://127.0.0.1:8500/**/**/articles/", host: "**.***.com", referrer: "http://**.***.com/new_article/"
列一下常见的几种502
对应的error_log
:
■ recv() failed (104: Connection reset by peer) while reading response header from upstream
■ upstream prematurely closed connection while reading response header from upstream
■ connect() failed (111: Connection refused) while connecting to upstream
■ ......
这些都代表,在nginx
设置的超时时间内,上游uwsgi
没有给正确的响应(但是是有响应的,不然如果一直没响应,就会变成504
超时了),因此nginx这边的状态码为502
。
如上,access_log
中出现503
,为什么?
这个是因为·nginx upstream·的容灾机制。如果·nginx·有如下配置:
upstream app_backup {
server 127.0.0.1:8500 max_fails=3 fail_timeout=5s;
server 127.0.0.1:88 backup;
}
2
3
4
max_fails=3
说明尝试3次后,会认为server 127.0.0.1:8500
失效,于是进入server 127.0.0.1:88 backup
,即访问本机的88
端口;
nginx upstream
的容灾机制,默认情况下,Nginx
默认判断失败节点状态以connect refuse
和time out
状态为准,不过location
里加了这个配置:
proxy_next_upstream error http_502;
proxy_connect_timeout 1s;
proxy_send_timeout 6s;
proxy_read_timeout 10s;
proxy_set_header Host $host;
2
3
4
5
这个配置是说,对于http
状态是502
的情况,也会走upstream
的容灾机制;
概括一下就是,如果连续有3次max_fails=3
状态为502
的请求,则会任务这个后端server 127.0.0.1:8500
挂掉了,在接下来的5s
(fail_timeout=5s
)内,就会访问backup
,即server 127.0.0.1:88
,看下88
端口对应的是什么:
server {
listen 88;
access_log /var/log/nginx/failover.log;
expires 1m;
error_page 500 502 503 504 /500.html;
location / {
return 503;
}
location = /500.html {
root /**/**/**/nginx/5xx/;
}
}
2
3
4
5
6
7
8
9
10
11
12
这个的意思就是,对于访问88
端口的请求,nginx
会返回503
状态码,同时返回/opt/tiger/ss_conf/nginx/5xx/
这个路径下的500.html
文件。因此,access_log
中看到的是503
。
Nginx 502 Bad Gateway
的含义是请求的PHP-CGI
已经执行,但是由于某种原因(一般是读取资源的问题)没有执行完毕而导致PHP-CGI
进程终止。Nginx 502
错误的原因比较多,一般就是因为在代理模式下后端服务器出现问题引起的。这些错误一般都不是nginx
本身的问题,一定要从后端找原因!比如:php-cgi
进程数不够用、php
执行时间长、或者是php-cgi
进程死掉,都会出现502
错误。502
错误最通常的出现情况就是后端主机宕机!!
一般来说Nginx 502 Bad Gateway
和php-fpm.conf
的设置有关,php-fpm.conf
有两个至关重要的参数,一个是max_children
,另一个是request_terminate_timeout
,但是这个值不是通用的,而是需要自己计算的。
计算的方式如下:
【1】request_terminate_timeout
:如果服务器性能足够好,且宽带资源足够充足,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
这个错误。
【2】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
这个错误。
# 502的解决办法:
一般解决办法:遇到502问题,可以优先考虑按照以下两个步骤去解决。
【1】查看当前的PHP FastCGI
进程数是否够用:
netstat -anpo | grep "php-cgi" | wc -l
如果实际使用的FastCGI
进程数接近预设的FastCGI
进程数,那么,说明FastCGI
进程数不够用,需要增大。
# ps aux | grep php-cgi |wc -l
130
# netstat -anpo | grep "php-cgi" | wc -l
450
# netstat -anpo | grep "php-cgi" |more
tcp 0 0 192.168.12.201:52719 192.168.12.203:13002 ESTABLISHED 27687/php-cgi off (0.00/0/0)
tcp 0 0 192.168.12.201:52713 192.168.12.203:13002 ESTABLISHED 27685/php-cgi off (0.00/0/0)
tcp 0 0 192.168.12.201:52694 192.168.12.203:13002 ESTABLISHED 27682/php-cgi off (0.00/0/0)
tcp 0 0 192.168.12.201:52688 192.168.12.203:13002 ESTABLISHED 27681/php-cgi off (0.00/0/0)
tcp 0 0 192.168.12.201:52701 192.168.12.203:13002 ESTABLISHED 27683/php-cgi off (0.00/0/0)
2
3
4
5
6
7
8
9
10
11
12
重启php
服务后
# netstat -anpo | grep "php-cgi" | wc -l
46
2
【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
为128M
,重启nginx
,发现好了,原来是PHP
的内存不足了。
临时解决办法:Nginx
提示502
和504
错误的临时解决办法是:调整php-fpm.conf
的相关设置:
<value name=”max_children”>32</value>
<value name=”request_terminate_timeout”>30s</value> <--fast-cgi的执行脚本时间-->
2
终级解决方案:以上解决方案只能临时解决问题,而如果网站的访问量确实非常非常大,而Nginx+FastCGI
只能对处理瞬间或短时间内的高并发有很好的效果,所以目前唯一的终极解决方案是:定时平滑重启php-cgi
。
【1】写一个非常简单的脚本:
# vim /home/www/scripts/php-fpm.sh
#!/bin/bash
# This script run at */1
/usr/local/php/sbin/php-fpm reload
2
3
4
【2】将脚本添加至计划任务:
# crontab -e
*/1 * * * * /home/www/scripts/php-fpm.sh
2
为了省事起见,也可以不写脚本,直接在crontab
里写入php-fpm
的平滑重启命令。
# Nginx 502错误情况
【1】网站的访问量大,而php-cgi
的进程数偏少:针对这种情况的502
错误,只需增加php-cgi
的进程数。具体就是修改/usr/local/php/etc/php-fpm.conf
文件,将其中的max_children
值适当增加。这个数据要依据你的VPS
或独立服务器的配置进行设置。一般一个php-cgi
进程占20M
内存,你可以自己计算下,适量增多。/usr/local/php/sbin/php-fpm restart
然后重启一下。
【2】CPU
占用率、内存占用率非常高,遭到CC攻击:解决方法请参考:Linux VPS
简单解决CC
攻击。
【3】CPU
占用率不高,内存溢出:检查一下网站程序有没有问题?一般小偷站点常常会出现内存溢出。检查一下/var/log/
目录下的日志,看看是不是有人爆破SSH
和FTP
端口?SSH
、FTP
遭到穷举也会占用大量内存。是的话改掉SSH
端口和FTP
端口即可。
# 四、499错误
client
发送请求后,如果在规定的时间内(假设超时时间为500ms
)没有拿到nginx
给的响应,则认为这次请求超时,会主动结束,这个时候nginx
的access_log
就会打印499
状态码。
A+B+C+D > 500ms
其实这个时候,server
端有可能还在处理请求,只不过client
断掉了连接,因此处理结果也无法返回给客户端。499
如果比较多的话,可能会引起服务雪崩。比如说,client
一直在发起请求,客户端因为某些原因处理慢了,没有在规定时间内返回数据,client
认为请求失败,中断这次请求,然后再重新发起请求。这样不断的重复,服务端的请求越来越多,机器负载变大,请求处理越来越慢,没有办法响应任何请求
官网总结nginx
返回499
的情况,是由于:
client has closed connection #客户端主动关闭了连接。
解决的话,可以添加
proxy_ignore_client_abort on;
还有一种原因,确实是客户端关闭了连接,或者连接超时。主要是因为PHP
进程数太少,或php
进程占用,资源不能很快释放,请求堆积。这种情况要解决的话,需要在程序上做优化。
499
报错即是客户端关闭连接,这个状态码并不是http
协议中定义的status code
,而是nginx
自己定义的一个状态码。由于服务器处理请求较多,客户端在有效时间内没有得到答复,主动关闭了连接。有人说把时间设置长一些或者使用proxy_ignore_client_abort on
(让代理服务端不要主动关闭客户端的连接)。但是这样也有一定的风险,会拖垮服务器。发生这个错误,如果服务器CPU
和内存不算太高,一般是数据库和程序的问题,数据库处理较慢或者程序线程较低。结合情况调整,比如读写分离或者程序线程数调高。
# 五、500错误
服务器内部错误,也就是服务器遇到意外情况,而无法执行请求。发生错误,一般的几种情况:
【1】web
脚本错误,如php
语法错误,lua
语法错误等。
【2】访问量大的时候,由于系统资源限制,而不能打开过多的文件句柄
分析错误的原因:
【1】查看nginx
,php
的错误日志
【2】如果是too many open files
,修改nginx
的worker_rlimit_nofile
参数,使用ulimit
查看系统打开文件限制,修改/etc/security/limits.conf
【3】如果脚本存在问题,则需要修复脚本错误,并优化代码
【4】各种优化都做好,还是出现too many open files
,那就需要考虑做负载均衡,把流量分散到不同服务器上去
# 六、503错误
503
是服务不可用的返回状态。由于在nginx
配置中,设置了limit_req
的流量限制,导致许多请求返回503
错误代码,在限流的条件下,为提高用户体验,希望返回正常Code 200
,且返回操作频繁的信息:
location /test {
...
limit_req zone=zone_ip_rm burst=1 nodelay;
error_page 503 =200 /dealwith_503?callback=$arg_callback;
}
location /dealwith_503{
set $ret_body '{"code": "V00006","msg": "操作太频繁了,请坐下来喝杯茶。"}';
if ( $arg_callback != "" )
{
return 200 'try{$arg_callback($ret_body)}catch(e){}';
}
return 200 $ret_body;
}
2
3
4
5
6
7
8
9
10
11
12
13
# 七、400错误
request header or cookie too large
解决办法:修改nginx.conf
,添加下面内容(即增加缓冲区)
[root@fvtlb01 ~]# vim /data/nginx/conf/nginx.conf
......
http
{
......
client_header_buffer_size 8k; #默认是4k(可以稍微改大,比如16K)
large_client_header_buffers 4 8k;
......
}
2
3
4
5
6
7
8
9
10
11
nginx
日志110: Connection timed out
报错: 访问nginx
页面,出现5xx
报错。查看nginx
日志,发现如下报错信息:
upstream timed out (110: Connection timed out) while reading response header from upstream
解决办法:修改fastcgi_read_timeout
的时间值,默认是60s
,比如可以改成600s
或3000s
# 八、Nginx Code Status
Code | 说明 |
---|---|
200 | 服务器成功返回网页 |
403 | 服务器拒绝请求 |
404 | 请求的网页不存在 |
499 | 客户端主动断开了连接 |
500 | 服务器遇到错误,无法完成请求 |
502 | 服务器作为网关或代理,从上游服务器收到无效响应 |
503 | 服务不可用 |
504 | 服务器作为网关或代理,但是没有及时从上游服务器收到请求 |
这些状态码被分为五大类:
Code | 说明 |
---|---|
100-199 | 用于指定客户端应相应的某些动作 |
200-299 | 用于表示请求成功 |
300-399 | 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息 |
400-499 | 用于指出客户端的错误。 (自己电脑这边的问题) 自己电脑这边的问题) |
500-599 | 用于支持服务器错误。 (对方的问题) 对方的问题) |
Code | 说明 |
---|---|
200 | (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页 |
201 | (已创建) 请求成功并且服务器创建了新的资源 |
202 | (已接受) 服务器已接受请求,但尚未处理 |
203 | (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源 |
204 | (无内容) 服务器成功处理了请求,但没有返回任何内容 |
205 | (重置内容) 服务器成功处理了请求,但没有返回任何内容 |
206 | (部分内容) 服务器成功处理了部分 GET 请求 |
Code | 说明 |
---|---|
300 | (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择 |
301 | (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置 |
302 | (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求 |
303 | (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码 |
304 | (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容 |
305 | (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理 |
307 | (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求 |
Code | 说明 |
---|---|
400 (错误请求) 服务器不理解请求的语法 | |
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应 | |
403 (禁止) 服务器拒绝请求 | |
404 (未找到) 服务器找不到请求的网页 | |
405 (方法禁用) 禁用请求中指定的方法 | |
406 (不接受) 无法使用请求的内容特性响应请求的网页 | |
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理 | |
408 (请求超时) 服务器等候请求时发生超时 | |
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息 | |
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应 | |
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求 | |
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件 | |
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力 | |
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理 | |
415 (不支持的媒体类型) 请求的格式不受请求页面的支持 | |
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码 | |
417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求 |
Code | 说明 |
---|---|
500 | (服务器内部错误) 服务器遇到错误,无法完成请求 |
501 | (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码 |
502 | (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应 |
503 | (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态 |
504 | (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求 |
505 | (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本 |
proxy_intercept_errors
:当上游服务器响应头回来后,可以根据响应状态码的值进行拦截错误处理,与error_page
指令相互结合。用在访问上游服务器出现错误的情况下。
如下的一个配置实例:
[root@dev ~]# cat ssl-zp.wangshibo.conf
upstream mianshi1 {
server 192.168.1.33:8080 max_fails=3 fail_timeout=10s;
#server 192.168.1.32:8080 max_fails=3 fail_timeout=10s;
}
server {
listen 443;
server_name zp.wangshibo.com;
ssl on;
### SSL log files ###
access_log logs/zrx_access.log;
error_log logs/zrx_error.log;
### SSL cert files ###
ssl_certificate ssl/wangshibo.cer;
ssl_certificate_key ssl/wangshibo.key;
ssl_session_timeout 5m;
error_page 404 301 https://zp.wangshibo.com/zrx-web/;
location /zrx-web/ {
proxy_pass http://mianshi1;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto https;
#proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
proxy_intercept_errors on;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
参考文献:https://www.cnblogs.com/kevingrace/p/7205623.html (opens new window)