您好,登錄后才能下訂單哦!
nginx常見狀態碼源碼分析是什么,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
最近生產環境出現502 報警較多,通過排查問題,有些問題還挺有意思。通過分析nginx 源碼,對查nginx 狀態碼來源可能會帶來一定啟發。本文基于1.6.2(主要是和生成環境對齊)。
首先常見的錯誤碼,定義在ngx_http_request.h, 這里有部分是client 引起的,有部分是upstream 引的,到底在什么情況下會引起下面這些問題?查問題從哪些方面入手?
#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 會打req 的status, 需要去查status 賦值邏輯。
grep -r status= src|grep 502
后端狀態碼5xx 的邏輯基本在ngx_http_upstream.c 的 ngx_http_upstream_next 中,這里是狀態碼的
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 有個對應關系,這里ft_error NGX_HTTP_UPSTREAM_FT_TIMEOUT 跟504 ,NGX_HTTP_UPSTREAM_FT_HTTP_500 和 500 等有一對一對應關系,其他的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 中有幾處會賦值,
第一處是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 中取連接,然后讀或者寫超時,可以看出504 的主要主要原因,是讀寫下游超時。
503 ,NGX_HTTP_SERVICE_UNAVAILABLE , grep 下就可以發現,主要是在limit 限流模塊會出現,
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 這里重置了狀態碼,而ngx_http_limit_req_merge_conf 會再 ngx_http_limit_conn_handler 中調用,這里限流被命中則返回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 相對比較復雜點,出現情況比較多。grep 502 , NGX_HTTP_BAD_GATEWAY 等實現,
1,可以看出ngx_resolve_start 在 resolve 階段,resolve 失敗會NGX_HTTP_BAD_GATEWAY
2, upstream->read/write 遇到eof / 0 /error 的時候會NGX_HTTP_BAD_GATEWAY, recv 系統調用返回n, 大于0時是讀寫字節數, 在接受到fin 的時候會返回0, 其他錯誤的時候返回-1。這里常見的一種錯就是,nginx 的下游掛了,會返回給上游一個fin,然后502 返回給client。
3,在upstream 連接階段,ngx_http_upstream_connect 連接下游失敗報錯會 傳 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 當是無效的header 的時候,NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 會傳給 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 時,如果主動close 了,nginx 就會記錄 499,這個狀態碼不會返回給client,只本地記錄。
看完上述內容,你們掌握nginx常見狀態碼源碼分析是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。