nginx常見(jiàn)狀態(tài)碼源碼分析是什么,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
創(chuàng)新互聯(lián)公司從2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元芮城做網(wǎng)站,已為上家服務(wù),為芮城各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18980820575
最近生產(chǎn)環(huán)境出現(xiàn)502 報(bào)警較多,通過(guò)排查問(wèn)題,有些問(wèn)題還挺有意思。通過(guò)分析nginx 源碼,對(duì)查nginx 狀態(tài)碼來(lái)源可能會(huì)帶來(lái)一定啟發(fā)。本文基于1.6.2(主要是和生成環(huán)境對(duì)齊)。
首先常見(jiàn)的錯(cuò)誤碼,定義在ngx_http_request.h, 這里有部分是client 引起的,有部分是upstream 引的,到底在什么情況下會(huì)引起下面這些問(wèn)題?查問(wèn)題從哪些方面入手?
#define NGX_HTTP_CLIENT_CLOSED_REQUEST 499 #define NGX_HTTP_INTERNAL_SERVER_ERROR 500 #define NGX_HTTP_NOT_IMPLEMENTED 501 #define NGX_HTTP_BAD_GATEWAY 502 #define NGX_HTTP_SERVICE_UNAVAILABLE 503 #define NGX_HTTP_GATEWAY_TIME_OUT 504 #define NGX_HTTP_INSUFFICIENT_STORAGE 507
access.log 會(huì)打req 的status, 需要去查status 賦值邏輯。
grep -r status= src|grep 502
后端狀態(tài)碼5xx 的邏輯基本在ngx_http_upstream.c 的 ngx_http_upstream_next 中,這里是狀態(tài)碼的
switch(ft_type) { case NGX_HTTP_UPSTREAM_FT_TIMEOUT: status = NGX_HTTP_GATEWAY_TIME_OUT; break; case NGX_HTTP_UPSTREAM_FT_HTTP_500: status = NGX_HTTP_INTERNAL_SERVER_ERROR; break; case NGX_HTTP_UPSTREAM_FT_HTTP_403: status = NGX_HTTP_FORBIDDEN; break; case NGX_HTTP_UPSTREAM_FT_HTTP_404: status = NGX_HTTP_NOT_FOUND; break;
這里ft_type 和 status 有個(gè)對(duì)應(yīng)關(guān)系,這里ft_error NGX_HTTP_UPSTREAM_FT_TIMEOUT 跟504 ,NGX_HTTP_UPSTREAM_FT_HTTP_500 和 500 等有一對(duì)一對(duì)應(yīng)關(guān)系,其他的ft type 都使用502 。這里就需要具體查下ft 的賦值情況。
#define NGX_HTTP_UPSTREAM_FT_ERROR 0x00000002 #define NGX_HTTP_UPSTREAM_FT_TIMEOUT 0x00000004 #define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 0x00000008 #define NGX_HTTP_UPSTREAM_FT_HTTP_500 0x00000010 #define NGX_HTTP_UPSTREAM_FT_HTTP_502 0x00000020 #define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000040 #define NGX_HTTP_UPSTREAM_FT_HTTP_504 0x00000080 #define NGX_HTTP_UPSTREAM_FT_HTTP_403 0x00000100 #define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000200 #define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000400 #define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000800 #define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00001000 #define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000 #define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000
504, NGX_HTTP_GATEWAY_TIME_OUT 在ngx_http_upstream.c 中有幾處會(huì)賦值,
第一處是ngx_http_upstream_process_upgraded,
if (downstream->write->timedout) { c->timedout = 1; ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out"); ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT); return; } if (upstream->read->timedout || upstream->write->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; }
第二處是 ngx_http_upstream_process_non_buffered_upstream
ngx_connection_t *c; c = u->peer.connection; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream process non buffered upstream"); c->log->action = "reading upstream"; if (c->read->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; } ngx_http_upstream_process_non_buffered_request(r, 0);
第三處是ngx_http_upstream_process_body_in_memory
c = u->peer.connection; rev = c->read; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream process body on memory"); if (rev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; }
三處都是從upstream 中取連接,然后讀或者寫超時(shí),可以看出504 的主要主要原因,是讀寫下游超時(shí)。
503 ,NGX_HTTP_SERVICE_UNAVAILABLE , grep 下就可以發(fā)現(xiàn),主要是在limit 限流模塊會(huì)出現(xiàn),
grep NGX_HTTP_SERVICE_UNAVAILABLE -r src src/http/modules/ngx_http_limit_req_module.c: NGX_HTTP_SERVICE_UNAVAILABLE); src/http/modules/ngx_http_limit_conn_module.c: NGX_HTTP_SERVICE_UNAVAILABLE);
源碼可以比較清晰看出來(lái)通過(guò) ngx_http_limit_req_merge_conf 這里重置了狀態(tài)碼,而ngx_http_limit_req_merge_conf 會(huì)再 ngx_http_limit_conn_handler 中調(diào)用,這里限流被命中則返回503
static ngx_int_t ngx_http_limit_conn_handler(ngx_http_request_t *r) { ... if (r->main->limit_conn_set) { return NGX_DECLINED; } lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module); limits = lccf->limits.elts; for (i = 0; i < lccf->limits.nelts; i++) { //處理每一條limit_conn策略 } return NGX_DECLINED; }
502 相對(duì)比較復(fù)雜點(diǎn),出現(xiàn)情況比較多。grep 502 , NGX_HTTP_BAD_GATEWAY 等實(shí)現(xiàn),
1,可以看出ngx_resolve_start 在 resolve 階段,resolve 失敗會(huì)NGX_HTTP_BAD_GATEWAY
2, upstream->read/write 遇到eof / 0 /error 的時(shí)候會(huì)NGX_HTTP_BAD_GATEWAY, recv 系統(tǒng)調(diào)用返回n, 大于0時(shí)是讀寫字節(jié)數(shù), 在接受到fin 的時(shí)候會(huì)返回0, 其他錯(cuò)誤的時(shí)候返回-1。這里常見(jiàn)的一種錯(cuò)就是,nginx 的下游掛了,會(huì)返回給上游一個(gè)fin,然后502 返回給client。
3,在upstream 連接階段,ngx_http_upstream_connect 連接下游失敗報(bào)錯(cuò)會(huì) 傳 NGX_HTTP_UPSTREAM_FT_ERROR 給ngx_http_upstream_next 。
rc = ngx_event_connect_peer(&u->peer); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream connect: %i", rc); if (rc == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } u->state->peer = u->peer.name; if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams"); ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE); return; } if (rc == NGX_DECLINED) { ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); return; }
4 當(dāng)是無(wú)效的header 的時(shí)候,NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 會(huì)傳給 ngx_http_upstream_next
if (u->buffer.last == u->buffer.end) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "upstream sent too big header"); ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER); return; }
499 相對(duì)而言就比較簡(jiǎn)單了, NGX_HTTP_CLIENT_CLOSED_REQUEST 在client 訪問(wèn)nginx 時(shí),如果主動(dòng)close 了,nginx 就會(huì)記錄 499,這個(gè)狀態(tài)碼不會(huì)返回給client,只本地記錄。
看完上述內(nèi)容,你們掌握nginx常見(jiàn)狀態(tài)碼源碼分析是什么的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!