最近查了一个线上页面503的问题,对nginx各种状态有了进一步的了解,简单的总结下。

由于现在的开发语言为python,所以拿nginx+uwsgi进行举例说明。

主要讲 504、502、499对应的场景

一个http请求处理流程

Alt text

一个普通的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; 
	...
}

这个代表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,意思是说,在规定的时间内,没有从header中拿到数据,即uwsgi没有返回任何数据。

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;
}
  • 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;                           
  • 这个配置是说,对于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/;
    }
}
  • 这个的意思就是,对于访问88端口的请求,nginx会返回503状态码,同时返回/opt/tiger/ss_conf/nginx/5xx/这个路径下的500.html文件。
  • 因此,access_log中看到的是503

499

client发送请求后,如果在规定的时间内(假设超时时间为500ms)没有拿到nginx给的响应,则认为这次请求超时,会主动结束,这个时候nginx的access_log就会打印499状态码。 A+B+C+D > 500ms

其实这个时候,server端有可能还在处理请求,只不过client断掉了连接,因此处理结果也无法返回给客户端。

499如果比较多的话,可能会引起服务雪崩。 比如说,client一直在发起请求,客户端因为某些原因处理慢了,没有在规定时间内返回数据,client认为请求失败,中断这次请求,然后再重新发起请求。这样不断的重复,服务端的请求越来越多,机器负载变大,请求处理越来越慢,没有办法响应任何请求。。

499 这个待补充。。