您好,登錄后才能下訂單哦!
nginx常見狀態(tài)碼源碼分析是什么,相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
最近生產(chǎn)環(huán)境出現(xiàn)502 報(bào)警較多,通過排查問題,有些問題還挺有意思。通過分析nginx 源碼,對查nginx 狀態(tài)碼來源可能會(huì)帶來一定啟發(fā)。本文基于1.6.2(主要是和生成環(huán)境對齊)。
首先常見的錯(cuò)誤碼,定義在ngx_http_request.h, 這里有部分是client 引起的,有部分是upstream 引的,到底在什么情況下會(huì)引起下面這些問題?查問題從哪些方面入手?
#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è)對應(yīng)關(guān)系,這里ft_error NGX_HTTP_UPSTREAM_FT_TIMEOUT 跟504 ,NGX_HTTP_UPSTREAM_FT_HTTP_500 和 500 等有一對一對應(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);
源碼可以比較清晰看出來通過 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 相對比較復(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。這里常見的一種錯(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)是無效的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 相對而言就比較簡單了, NGX_HTTP_CLIENT_CLOSED_REQUEST 在client 訪問nginx 時(shí),如果主動(dòng)close 了,nginx 就會(huì)記錄 499,這個(gè)狀態(tài)碼不會(huì)返回給client,只本地記錄。
看完上述內(nèi)容,你們掌握nginx常見狀態(tài)碼源碼分析是什么的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。