Nginx 報(bào) 502、504、連接超時(shí),看起來都是“請求沒成功”,但根因完全不是一類問題。502 更多是上游服務(wù)直接返回?zé)o效響應(yīng)、連接被拒絕或進(jìn)程掛了;504 更像是請求已經(jīng)到上游,但超時(shí)窗口內(nèi)沒處理完;連接超時(shí)則要分清楚是客戶端連不到 Nginx,還是 Nginx 連不上 upstream,還是三次握手卡在內(nèi)核隊(duì)列里。
線上處理這類問題,最忌諱拿著錯(cuò)誤碼直接拍腦袋。我的習(xí)慣是先把路徑拆成四段:客戶端 -> Nginx -> upstream -> 內(nèi)核/網(wǎng)絡(luò)。只要能定位出哪一段開始失敗,排障速度會(huì)快很多。
一、概述
1.1 背景介紹
Nginx 是很多業(yè)務(wù)的入口層和反向代理層,一旦出現(xiàn) 502、504 或連接超時(shí),業(yè)務(wù)側(cè)感知通常很直接:
網(wǎng)關(guān)返回 5xx,接口成功率快速下降
頁面首屏打開慢,靜態(tài)資源加載卡住
上游服務(wù)監(jiān)控看起來還活著,但外部流量已經(jīng)受影響
這篇手冊解決的是三類高頻問題:
Nginx 為何會(huì)報(bào) 502,常見故障點(diǎn)在哪
504 和 upstream 超時(shí)要從哪些配置和指標(biāo)入手
連接超時(shí)到底是連接數(shù)、backlog、網(wǎng)絡(luò)還是服務(wù)端處理慢
1.2 技術(shù)特點(diǎn)
按鏈路拆解:把一個(gè)錯(cuò)誤碼拆成監(jiān)聽層、代理層、上游層、內(nèi)核層四個(gè)檢查點(diǎn)
日志和連接狀態(tài)聯(lián)動(dòng):錯(cuò)誤日志、訪問日志、ss/netstat、應(yīng)用日志同時(shí)看,避免單點(diǎn)誤判
面向生產(chǎn)修復(fù):不只給“怎么看”,還給“怎么止血、怎么回滾、怎么預(yù)防”
1.3 適用場景
業(yè)務(wù)網(wǎng)關(guān)、API 網(wǎng)關(guān)、反向代理層出現(xiàn) 502/504 告警
靜態(tài)資源服務(wù)、Web 接入層、Kubernetes Ingress Nginx 出現(xiàn)突發(fā)超時(shí)
微服務(wù)架構(gòu)中 Nginx 代理 Java、Go、PHP-FPM、Node.js upstream 時(shí)故障頻發(fā)
1.4 環(huán)境要求
| 組件 | 版本要求 | 說明 |
|---|---|---|
| 操作系統(tǒng) | CentOS 7/8、Rocky Linux 8/9、Ubuntu 20.04+ | 命令覆蓋主流生產(chǎn)環(huán)境 |
| Nginx | 1.18+ 或 OpenResty 1.19+ | 文中參數(shù)以常用穩(wěn)定版本為準(zhǔn) |
| 上游服務(wù) | HTTP、FastCGI、uWSGI、gRPC | 案例主要以 HTTP upstream 和 PHP-FPM 為例 |
| 診斷工具 | ss 、curl、tcpdump、ngxtop、strace | 用于連接、日志和抓包定位 |
二、詳細(xì)步驟
2.1 準(zhǔn)備工作
2.1.1 系統(tǒng)檢查
先確認(rèn)是“真的大面積失敗”,還是健康檢查、個(gè)別 URI 或個(gè)別 upstream 節(jié)點(diǎn)異常。第一輪命令我一般這么打:
date hostname -f nginx -V nginx -t systemctl status nginx --no-pager ss -lntp | grep':80|:443' ss -s curl -I -m 3 http://127.0.0.1/ tail -n 50 /var/log/nginx/error.log tail -n 50 /var/log/nginx/access.log
第一輪要回答五個(gè)問題:
Nginx 進(jìn)程是不是活著,配置有沒有語法問題
錯(cuò)誤碼主要是 502、504 還是連接超時(shí)
是所有站點(diǎn)都異常,還是某個(gè)server/location異常
是所有 upstream 都失敗,還是個(gè)別節(jié)點(diǎn)失敗
錯(cuò)誤發(fā)生時(shí)連接數(shù)、重傳、backlog 有沒有異常
常見日志關(guān)鍵詞要先掃一遍:
grep -E"connect() failed|upstream timed out|no live upstreams|recv() failed|connection refused|broken pipe|reset by peer"/var/log/nginx/error.log | tail -100
這些關(guān)鍵詞基本能把故障定到某一層:
connect() failed (111: Connection refused):上游沒監(jiān)聽、進(jìn)程掛了、防火墻攔了
upstream timed out (110: Connection timed out):請求到上游了,但在超時(shí)窗口內(nèi)沒處理完
no live upstreams:upstream 全部不可用,通常是健康檢查或全部失敗
recv() failed (104: Connection reset by peer):上游主動(dòng)斷開連接
2.1.2 安裝依賴
# Debian / Ubuntu sudo apt update sudo apt install -y curl tcpdump ngrep apache2-utils jq lsof dnsutils # RHEL / CentOS / Rocky sudo yum install -y curl tcpdump ngrep httpd-tools jq lsofbind-utils
如果機(jī)器沒裝stub_status或 Prometheus Exporter,排障時(shí)信息會(huì)少很多。生產(chǎn)環(huán)境建議默認(rèn)開一個(gè)只內(nèi)網(wǎng)可訪問的狀態(tài)頁。
2.2 核心配置與排查步驟
2.2.1 第一步:把錯(cuò)誤定位到哪一段鏈路
這一步先區(qū)分是客戶端到 Nginx、Nginx 到 upstream、還是 upstream 內(nèi)部處理超時(shí)。
curl -sS -o /dev/null -w'code=%{http_code} connect=%{time_connect} start=%{time_starttransfer} total=%{time_total}
'http://127.0.0.1/api/health
curl -sS -o /dev/null -w'code=%{http_code} connect=%{time_connect} start=%{time_starttransfer} total=%{time_total}
'http://:/health
ss -ant state syn-recv
ss -ant state time-wait | wc -l
判斷思路:
本機(jī)訪問 Nginx 正常,但外部訪問超時(shí):優(yōu)先查防火墻、L4 負(fù)載均衡、證書、網(wǎng)絡(luò) ACL
本機(jī)訪問 Nginx 502,直連 upstream 也失?。簡栴}在 upstream
本機(jī)訪問 Nginx 504,直連 upstream 響應(yīng)慢:問題在 upstream 處理時(shí)長
本機(jī)訪問 Nginx 慢,直連 upstream 正常:問題多半在 Nginx 配置、DNS、連接復(fù)用或內(nèi)核連接隊(duì)列
2.2.2 第二步:檢查 upstream 配置和超時(shí)參數(shù)
Nginx 排障時(shí),配置不能只看有沒有寫錯(cuò),還要看值是不是符合業(yè)務(wù)流量模型。下面這幾個(gè)參數(shù)最常出事故:
upstream order_service {
least_conn;
server 10.10.20.31:8080 max_fails=3 fail_timeout=10s;
server 10.10.20.32:8080 max_fails=3 fail_timeout=10s;
keepalive 128;
}
server {
listen 80 reuseport backlog=65535;
server_name api.example.com;
access_log /var/log/nginx/api.access.log main_ext;
error_log /var/log/nginx/api.error.log warn;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
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_connect_timeout 2s;
proxy_send_timeout 10s;
proxy_read_timeout 15s;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 2;
proxy_pass http://order_service;
}
}
關(guān)鍵參數(shù)解釋:
proxy_connect_timeout:Nginx 連 upstream 的時(shí)間,不建議無腦拉大
proxy_read_timeout:Nginx 等待 upstream 響應(yīng)的時(shí)間,和業(yè)務(wù)接口 SLA 強(qiáng)相關(guān)
keepalive:upstream 長連接池大小,過小會(huì)增加建連成本,過大又會(huì)壓上游連接數(shù)
backlog:監(jiān)聽隊(duì)列長度,流量突發(fā)時(shí)太小容易丟連接
proxy_next_upstream_tries:失敗重試次數(shù),設(shè)太大可能放大雪崩
生產(chǎn)環(huán)境里,超時(shí)參數(shù)最好分接口類型配置,不要全站統(tǒng)一一個(gè)值。支付回調(diào)、導(dǎo)出任務(wù)、普通查詢接口的超時(shí)窗口本來就不該一樣。
2.2.3 第三步:結(jié)合錯(cuò)誤日志定位 502、504、超時(shí)模式
錯(cuò)誤日志是這類故障的核心證據(jù)。下面這組命令建議固定成模板:
tail -f /var/log/nginx/error.log
grep -E" 502 | 504 "/var/log/nginx/access.log | tail -50
awk'$9 ~ /502|504/ {print $4,$5,$7,$9,$10,$11}'/var/log/nginx/access.log | tail -50
grep -E"connect() failed|upstream timed out|reset by peer|no live upstreams"/var/log/nginx/error.log | tail -100
我一般按下面方式定性:
502 + connection refused:upstream 端口沒監(jiān)聽、進(jìn)程掛了、容器未就緒
502 + reset by peer:上游主動(dòng)斷開,常見于上游線程池滿、進(jìn)程崩潰、FD 打滿
504 + upstream timed out:上游還活著,但處理不過來,可能是慢 SQL、鎖等待、外部依賴阻塞
客戶端連接超時(shí):要查worker_connections、backlog、系統(tǒng)連接隊(duì)列、SYN flood、L4 轉(zhuǎn)發(fā)路徑
2.3 啟動(dòng)和驗(yàn)證
2.3.1 重新加載配置
排查過程中經(jīng)常需要臨時(shí)打開更詳細(xì)日志或調(diào)高某個(gè)接口超時(shí)。改配置前先做語法檢查和備份。
sudo cp -a /etc/nginx /etc/nginx.$(date +%F_%H%M%S).bak sudo nginx -t sudo nginx -s reload sudo systemctl status nginx --no-pager
如果是高峰期,優(yōu)先做最小化修改,不要順手一起改 upstream 策略、緩存策略和 gzip 參數(shù),容易把故障面擴(kuò)大。
2.3.2 功能驗(yàn)證
# 驗(yàn)證命令
curl -sS -o /dev/null -w'code=%{http_code} connect=%{time_connect} start=%{time_starttransfer} total=%{time_total}
'http://127.0.0.1/api/ping
ab -n 500 -c 50 http://127.0.0.1/api/ping
# 預(yù)期輸出
# code=200 connect<0.01 start<0.1 total<0.2
驗(yàn)證時(shí)不要只看 HTTP 200。還要同時(shí)看:
error.log是否還在刷 502/504
upstream 實(shí)例錯(cuò)誤率是否同步下降
ss -s中estab/syn-recv/time-wait是否回到正常區(qū)間
三、示例代碼和配置
3.1 完整配置示例
3.1.1 主配置文件
下面這份配置適合生產(chǎn)網(wǎng)關(guān)場景,重點(diǎn)是把日志字段打全,并給 upstream 長連接、超時(shí)和失敗重試一個(gè)穩(wěn)妥基線。
# 文件路徑:/etc/nginx/conf.d/api_gateway.conf log_format main_ext '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'rt=$request_time urt=$upstream_response_time ' 'uaddr=$upstream_addr ustatus=$upstream_status ' 'xff="$http_x_forwarded_for" host="$host" ' 'reqid="$request_id"'; upstream api_backend { least_conn; keepalive 256; server 10.10.30.21:8080 max_fails=3 fail_timeout=10s; server 10.10.30.22:8080 max_fails=3 fail_timeout=10s; server 10.10.30.23:8080 backup; } server { listen 80 reuseport backlog=65535; server_name api.example.com; access_log /var/log/nginx/api.access.log main_ext; error_log /var/log/nginx/api.error.log warn; client_header_timeout 10s; client_body_timeout 15s; keepalive_timeout 30s; keepalive_requests 1000; send_timeout 10s; location /nginx_status { stub_status; allow 127.0.0.1; allow 10.10.0.0/16; deny all; } location / { proxy_http_version 1.1; proxy_set_header Connection ""; 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-Request-Id $request_id; proxy_connect_timeout 2s; proxy_send_timeout 10s; proxy_read_timeout 15s; proxy_buffering on; proxy_buffers 16 32k; proxy_busy_buffers_size 128k; proxy_next_upstream error timeout http_502 http_503 http_504; proxy_next_upstream_tries 2; proxy_pass http://api_backend; } }
這份配置里最有價(jià)值的是兩點(diǎn):
access_log里把request_time、upstream_response_time、upstream_addr、upstream_status全打出來,定位 502/504 時(shí)能直接看出是哪臺(tái) upstream 出問題
proxy_next_upstream_tries只設(shè) 2,避免 upstream 已經(jīng)慢死了,Nginx 還繼續(xù)重試放大壓力
3.1.2 輔助腳本
這份腳本用于快速統(tǒng)計(jì)最近 5 分鐘的 502、504 和連接失敗日志,值班時(shí)很實(shí)用,不用每次都手敲awk。
#!/usr/bin/env bash
# 文件名:/usr/local/bin/nginx_5xx_report.sh
# 功能:統(tǒng)計(jì) Nginx 近 5 分鐘 502/504/超時(shí)情況,并輸出熱點(diǎn) upstream
set-euo pipefail
ACCESS_LOG="/var/log/nginx/api.access.log"
ERROR_LOG="/var/log/nginx/api.error.log"
START_TS="$(date -d '5 minutes ago' '+%d/%b/%Y:%H:%M')"
echo"== 近 5 分鐘 access 日志中的 5xx 統(tǒng)計(jì) =="
awk -v start="$START_TS"'
index($4, start) || seen {
seen=1
if ($9 ~ /^50[24]$/) {
total[$9]++
upstream[$0]++
}
}
END {
for (code in total) {
printf "%s => %d
", code, total[code]
}
}'"$ACCESS_LOG"
echo
echo"== 最近 100 條錯(cuò)誤日志中的熱點(diǎn)錯(cuò)誤 =="
tail -100"$ERROR_LOG"|
egrep'connect() failed|upstream timed out|reset by peer|no live upstreams'|
sort | uniq -c | sort -nr
echo
echo"== 當(dāng)前連接概覽 =="
ss -s
echo
echo"== 當(dāng)前 nginx status =="
curl -s http://127.0.0.1/nginx_status ||true
部署建議:
sudo install -o root -g root -m 0750 nginx_5xx_report.sh /usr/local/bin/nginx_5xx_report.sh
3.2 實(shí)際應(yīng)用案例
案例一:502 原因是 upstream 進(jìn)程異常退出
場景描述:支付網(wǎng)關(guān)突然出現(xiàn)大量 502,錯(cuò)誤率從 0.02% 拉到 6% 左右。Nginx 本身 CPU 和內(nèi)存都正常,外部流量也沒有異常放大。
排查過程:
grep" 502 "/var/log/nginx/api.access.log | tail -20 grep"connect() failed"/var/log/nginx/api.error.log | tail -20 ss -lntp | grep 8080 systemctl status pay-service --no-pager journalctl -u pay-service -S -10min
關(guān)鍵現(xiàn)象:
error.log中大量出現(xiàn)connect() failed (111: Connection refused) while connecting to upstream
8080 端口監(jiān)聽間歇性消失
上游服務(wù)日志顯示 JVM 被 OOM Killer 殺掉
實(shí)現(xiàn)代碼:
grep -E"OutOfMemoryError|Killed process"/var/log/messages /var/log/syslog /var/log/pay-service/app.log
處理動(dòng)作:
先把故障 upstream 從負(fù)載均衡摘掉
拉起服務(wù),確認(rèn)端口恢復(fù)監(jiān)聽
限制異常流量,防止恢復(fù)后再次被打掛
追加 JVM 堆、連接池和線程池監(jiān)控
運(yùn)行結(jié)果:
處理前:502 錯(cuò)誤率 6.1%,支付回調(diào)積壓 1.8 萬條 處理后:5 分鐘內(nèi) 502 降到 0.05%,回調(diào)堆積逐步消化
案例二:504 根因是慢 SQL 拖垮 upstream
場景描述:營銷活動(dòng)開始后,商品查詢接口連續(xù)出現(xiàn) 504。Nginx 的proxy_read_timeout設(shè)為 15 秒,業(yè)務(wù)方第一反應(yīng)是把超時(shí)改成 60 秒。
這個(gè)方向是錯(cuò)的。超時(shí)拉長只會(huì)讓連接占得更久,雪崩來得更快。
排查過程:
grep"upstream timed out"/var/log/nginx/api.error.log | tail -20
awk'$9 == 504 {print $7,$9,$11,$12}'/var/log/nginx/api.access.log | tail -20
curl -sS -o /dev/null -w'code=%{http_code} total=%{time_total}
'http://10.10.30.21:8080/api/product/list
mysql -e"show full processlist;"
mysql -e"show engine innodb statusG"| egrep -i'lock wait|wait'
關(guān)鍵現(xiàn)象:
Nginx 錯(cuò)誤日志明確提示upstream timed out
upstream 直連同樣慢,響應(yīng)時(shí)間 18-25 秒
數(shù)據(jù)庫里出現(xiàn)多條全表掃描慢 SQL,鎖等待時(shí)間長
實(shí)現(xiàn)步驟:
先對活動(dòng)接口做限流,保護(hù)連接池
在數(shù)據(jù)庫側(cè)殺掉異常慢 SQL
緊急加索引并回滾有問題的查詢邏輯
恢復(fù)后把upstream_response_time和慢 SQL 告警聯(lián)動(dòng)
運(yùn)行結(jié)果:
處理前:504 錯(cuò)誤率 12.4%,接口 P99 22.7s 處理后:接口 P99 回落到 320ms,504 基本清零
四、最佳實(shí)踐和注意事項(xiàng)
4.1 最佳實(shí)踐
4.1.1 性能優(yōu)化
優(yōu)化點(diǎn)一:日志字段一次打全,故障時(shí)少走彎路
沒有upstream_response_time、upstream_status、upstream_addr的訪問日志,排 502/504 基本只能靠猜。日志量會(huì)變大,但這個(gè)成本遠(yuǎn)低于故障期間盲查。
sudo nginx -t sudo nginx -s reload
優(yōu)化點(diǎn)二:上游連接池和超時(shí)按業(yè)務(wù)類型拆分
同一個(gè)proxy_read_timeout套所有接口,遲早要踩坑。支付、搜索、導(dǎo)出、上傳這幾類接口處理時(shí)長差異很大,應(yīng)該拆location或拆獨(dú)立域名配置。
location /api/export/ {
proxy_read_timeout 60s;
proxy_pass http://export_backend;
}
優(yōu)化點(diǎn)三:避免失敗重試放大雪崩
上游已經(jīng)慢了,再讓 Nginx 多次重試,會(huì)把連接、線程、數(shù)據(jù)庫壓力一起放大。實(shí)測下來,高峰期proxy_next_upstream_tries大于 2 的配置經(jīng)常會(huì)讓故障擴(kuò)散得更快。
4.1.2 安全加固
安全措施一:狀態(tài)頁只允許內(nèi)網(wǎng)訪問
stub_status很好用,但別直接暴露到公網(wǎng)。
location /nginx_status {
stub_status;
allow 127.0.0.1;
allow 10.10.0.0/16;
deny all;
}
安全措施二:限制大請求和慢客戶端
很多連接超時(shí)并不是 upstream 慢,而是慢客戶端一直占著連接不放??梢酝ㄟ^請求體大小、頭部超時(shí)和發(fā)送超時(shí)做約束。
client_max_body_size 20m; client_header_timeout 10s; client_body_timeout 15s; send_timeout 10s;
安全措施三:對 reload 和配置變更做審計(jì)
Nginx 故障很多發(fā)生在發(fā)布后或臨時(shí)調(diào)整后。把nginx.conf、conf.d/目錄和 reload 操作納入審計(jì),比事后追人靠譜。
4.1.3 高可用配置
HA 方案一:upstream 至少保留 2 個(gè)可用節(jié)點(diǎn),關(guān)鍵接口保留 1 個(gè)backup節(jié)點(diǎn)
HA 方案二:入口層做多機(jī)房或多可用區(qū)部署,避免單點(diǎn)網(wǎng)關(guān)故障
備份策略:每次變更前歸檔/etc/nginx,并記錄 reload 時(shí)間點(diǎn)、變更單號(hào)和負(fù)責(zé)人
sudo tar czf /var/backups/nginx-$(date +%F_%H%M%S).tar.gz /etc/nginx
4.2 注意事項(xiàng)
4.2.1 配置注意事項(xiàng)
警告:出現(xiàn) 504 時(shí)不要第一反應(yīng)拉大proxy_read_timeout。如果根因是 upstream 卡住、數(shù)據(jù)庫慢、鎖等待,拉長超時(shí)只會(huì)讓連接占用時(shí)間更長,入口層更容易被拖死。
注意事項(xiàng)一:worker_connections不等于最大并發(fā)數(shù),實(shí)際還受worker_processes、文件描述符和 upstream 連接數(shù)限制
注意事項(xiàng)二:keepalive_timeout設(shè)太長會(huì)占住連接,設(shè)太短又會(huì)增加頻繁建連開銷,要結(jié)合客戶端類型調(diào)
注意事項(xiàng)三:proxy_buffering關(guān)閉后排障更直觀,但高流量下會(huì)增加 upstream 壓力,不要高峰期隨便改
4.2.2 常見錯(cuò)誤
| 錯(cuò)誤現(xiàn)象 | 原因分析 | 解決方案 |
|---|---|---|
| 504 一出現(xiàn)就把超時(shí)參數(shù)翻倍 | 沒確認(rèn) upstream 真實(shí)處理時(shí)長 | 先直連 upstream,看數(shù)據(jù)庫、線程池、依賴服務(wù) |
| 502 一出現(xiàn)就重啟 Nginx | 問題通常不在 Nginx 主進(jìn)程 | 先看error.log,確認(rèn)是否是 upstream 拒絕連接或重置連接 |
| 連接超時(shí)就加機(jī)器,不看連接隊(duì)列 | 可能是 backlog、FD、SYN flood 或防火墻 | 查ss -s、netstat -s、sysctl和抓包結(jié)果 |
4.2.3 兼容性問題
版本兼容:不同 Nginx/OpenResty 版本對部分模塊和日志變量支持不同,升級(jí)前先做灰度
平臺(tái)兼容:容器環(huán)境里worker_processes auto要結(jié)合 CPU limit 看,別按宿主機(jī)核數(shù)誤判
組件依賴:代理 PHP-FPM 時(shí),還要額外檢查fastcgi_*參數(shù)、pm.max_children和 socket backlog
五、故障排查和監(jiān)控
5.1 故障排查
5.1.1 日志查看
Nginx 故障排查,日志順序建議固定成:error.log -> access.log -> upstream 應(yīng)用日志 -> 系統(tǒng)日志。
# 查看系統(tǒng)日志
sudo journalctl -u nginx -S -30min
# 查看 Nginx 錯(cuò)誤日志
tail -f /var/log/nginx/api.error.log
# 查看 502/504 請求
awk'$9 ~ /502|504/ {print $4,$7,$9,$10,$11,$12}'/var/log/nginx/api.access.log | tail -50
如果是 PHP-FPM 或 uWSGI,再補(bǔ)對應(yīng)日志:
tail -f /var/log/php-fpm/www-error.log tail -f /var/log/uwsgi/app.log
5.1.2 常見問題排查
問題一:大量 502,錯(cuò)誤日志提示connection refused
grep"connect() failed"/var/log/nginx/api.error.log | tail -20 ss -lntp | grep 8080 systemctl status app-service --no-pager
癥狀:502 激增,upstream 端口偶爾不監(jiān)聽
診斷:上游進(jìn)程崩潰、未拉起、健康檢查未通過或被防火墻攔截
解決:
先摘掉故障 upstream
拉起服務(wù)并確認(rèn)監(jiān)聽恢復(fù)
檢查 OOM、core、配置錯(cuò)誤或啟動(dòng)腳本問題
問題二:大量 504,日志提示upstream timed out
grep"upstream timed out"/var/log/nginx/api.error.log | tail -20
curl -sS -o /dev/null -w'code=%{http_code} total=%{time_total}
'http://:/health
癥狀:接口響應(yīng)越來越慢,504 比例持續(xù)升高
診斷:上游處理時(shí)長超出proxy_read_timeout,根因常在慢 SQL、線程池排隊(duì)、外部依賴超時(shí)
解決:
限流或摘掉最慢接口
查上游應(yīng)用線程池、GC、數(shù)據(jù)庫、依賴服務(wù)
只在確認(rèn) SLA 允許時(shí)小幅調(diào)整超時(shí)窗口
問題三:客戶端連接超時(shí),但 Nginx error.log 沒明顯報(bào)錯(cuò)
癥狀:用戶連接建立慢或握手失敗,Nginx 日志很干凈
排查:ss -s、ss -lnt、netstat -s | egrep -i 'listen|overflow|drop|retrans'、抓包看三次握手
解決:檢查somaxconn、tcp_max_syn_backlog、worker_connections、L4 轉(zhuǎn)發(fā)和安全設(shè)備
5.1.3 調(diào)試模式
Nginx 默認(rèn)錯(cuò)誤日志級(jí)別不一定夠用,排障時(shí)可以局部提到info或debug,但不要長時(shí)間開全局 debug。
# 臨時(shí)提升某個(gè)站點(diǎn)日志級(jí)別 sudo sed -i's/error_log /var/log/nginx/api.error.log warn;/error_log /var/log/nginx/api.error.log info;/'/etc/nginx/conf.d/api_gateway.conf sudo nginx -t && sudo nginx -s reload # 查看連接和請求狀態(tài) curl -s http://127.0.0.1/nginx_status
需要抓包時(shí)只抓必要端口和時(shí)間窗:
sudo timeout 30 tcpdump -i any -nn hostand port 8080 -w /tmp/nginx_upstream_timeout.pcap
5.2 性能監(jiān)控
5.2.1 關(guān)鍵指標(biāo)監(jiān)控
# 連接狀態(tài)
ss -s
# Nginx status
curl -s http://127.0.0.1/nginx_status
# 錯(cuò)誤碼占比
awk'{print $9}'/var/log/nginx/api.access.log | sort | uniq -c | sort -nr | head
# FD 使用
cat /proc/$(cat /run/nginx.pid)/limits | grep"open files"
關(guān)鍵監(jiān)控項(xiàng)建議包括:
nginx_http_requests_total
nginx_connections_active/reading/writing/waiting
5xx比例、upstream_response_time分位數(shù)
accepts/handled差值
主機(jī) TCP 重傳、listen overflow、SYN backlog
5.2.2 監(jiān)控指標(biāo)說明
| 指標(biāo)名稱 | 正常范圍 | 告警閾值 | 說明 |
|---|---|---|---|
| 502 錯(cuò)誤率 | 接近 0 | 1 分鐘高于 1% | 多與 upstream 拒絕連接、重置連接有關(guān) |
| 504 錯(cuò)誤率 | 接近 0 | 1 分鐘高于 0.5% | 多與 upstream 處理超時(shí)有關(guān) |
| upstream_response_time P99 | 小于接口 SLA | 超出基線 2 倍 | 先看 upstream,再看入口超時(shí)參數(shù) |
| 活躍連接數(shù) | 隨業(yè)務(wù)波動(dòng) | 接近設(shè)計(jì)容量 80% | 結(jié)合worker_connections和 FD 使用率看 |
| SYN-RECV 數(shù) | 低位波動(dòng) | 持續(xù)升高 | 可能是 backlog 不足或攻擊流量 |
| 打開文件數(shù)使用率 | 低于 70% | 高于 85% | FD 打滿會(huì)引發(fā)連接失敗和 502 |
5.2.3 監(jiān)控告警配置
# 文件路徑:prometheus/rules/nginx_5xx.yml
groups:
-name:nginx-5xx
rules:
-alert:Nginx502RateHigh
expr:|
sum(rate(nginx_http_requests_total{status="502"}[1m])) by (instance)
/
sum(rate(nginx_http_requests_total[1m])) by (instance) > 0.01
for:2m
labels:
severity:critical
annotations:
summary:"Nginx 502 錯(cuò)誤率過高"
description:"{{ $labels.instance }}近 2 分鐘 502 比例超過 1%"
-alert:Nginx504RateHigh
expr:|
sum(rate(nginx_http_requests_total{status="504"}[1m])) by (instance)
/
sum(rate(nginx_http_requests_total[1m])) by (instance) > 0.005
for:2m
labels:
severity:critical
annotations:
summary:"Nginx 504 錯(cuò)誤率過高"
description:"{{ $labels.instance }}近 2 分鐘 504 比例超過 0.5%"
-alert:NginxUpstreamP99High
expr:histogram_quantile(0.99,sum(rate(nginx_upstream_response_time_bucket[5m]))by(le,instance))>3
for:5m
labels:
severity:warning
annotations:
summary:"Nginx upstream P99 響應(yīng)偏高"
description:"{{ $labels.instance }}upstream P99 超過 3 秒"
5.3 備份與恢復(fù)
5.3.1 備份策略
Nginx 配置修改前先備份目錄,不要只備份單個(gè)文件。線上故障時(shí),很多人會(huì)連帶改upstream、日志、限流和緩存參數(shù),單文件備份不夠。
#!/usr/bin/env bash
# 文件名:/usr/local/bin/backup_nginx_config.sh
set-euo pipefail
TARGET="/var/backups/nginx-config-$(date +%F_%H%M%S).tar.gz"
tar czf"${TARGET}"/etc/nginx
echo"backup saved to${TARGET}"
5.3.2 恢復(fù)流程
停止繼續(xù)變更:暫停自動(dòng)發(fā)布、暫停額外配置調(diào)整
恢復(fù)上一版配置:還原備份目錄或從 Git/配置中心回滾
驗(yàn)證完整性:執(zhí)行nginx -t,確認(rèn)語法、證書、include 路徑都正常
熱加載服務(wù):nginx -s reload后立即驗(yàn)證 200、502、504 指標(biāo)
六、總結(jié)
6.1 技術(shù)要點(diǎn)回顧
502 和 504 不是一回事:502 更偏連接失敗、無效響應(yīng)、進(jìn)程異常;504 更偏 upstream 處理超時(shí)
先分鏈路再排障:客戶端、Nginx、upstream、內(nèi)核網(wǎng)絡(luò)四層拆開看,定位速度快很多
錯(cuò)誤日志是核心證據(jù):connect() failed、upstream timed out、reset by peer這幾個(gè)關(guān)鍵詞很關(guān)鍵
超時(shí)參數(shù)不能亂拉大:很多時(shí)候真正該修的是 upstream、數(shù)據(jù)庫或線程池,不是 Nginx 超時(shí)值
連接超時(shí)要看隊(duì)列和內(nèi)核:worker_connections、FD、somaxconn、tcp_max_syn_backlog都會(huì)影響表現(xiàn)
日志字段和監(jiān)控維度要打全:沒有upstream_response_time、upstream_status,排 5xx 會(huì)很被動(dòng)
6.2 進(jìn)階學(xué)習(xí)方向
深入理解 Nginx 事件模型和連接生命周期
學(xué)習(xí)資源:Nginx 官方文檔、源碼中的 event/HTTP 模塊
實(shí)踐建議:結(jié)合stub_status和壓測工具觀察連接狀態(tài)變化
掌握 upstream 類型差異
學(xué)習(xí)資源:HTTP proxy、FastCGI、uWSGI、gRPC 官方模塊文檔
實(shí)踐建議:分場景調(diào)試proxy_*、fastcgi_*、grpc_*參數(shù)
建立入口層故障聯(lián)動(dòng)機(jī)制
學(xué)習(xí)資源:Prometheus、Alertmanager、日志平臺(tái)、自動(dòng)摘流工具
實(shí)踐建議:把 502/504 告警和 upstream 健康檢查、數(shù)據(jù)庫慢查詢聯(lián)動(dòng)到一起
6.3 參考資料
Nginx 官方文檔- Nginx 核心模塊與參數(shù)說明
Nginx reverse proxy guide- 反向代理與 upstream 配置建議
Linux TCP tuning guide- TCP 隊(duì)列和內(nèi)核參數(shù)說明
OpenResty 文檔- OpenResty/Nginx 生產(chǎn)實(shí)踐資料
附錄
A. 命令速查表
nginx -t # 檢查配置語法
nginx -s reload # 熱加載配置
ss -s # 查看連接概況
ss -lntp | grep':80|:443' # 查看監(jiān)聽狀態(tài)
grep"connect() failed"/var/log/nginx/error.log # 查 upstream 拒絕連接
grep"upstream timed out"/var/log/nginx/error.log# 查 upstream 超時(shí)
curl -I -m 3 http://127.0.0.1/ # 本機(jī)驗(yàn)證入口層
curl -sS -o /dev/null -w'%{http_code} %{time_total}
'http://:/health # 直連 upstream
tcpdump -i any -nn host and port # 抓 upstream 通信
B. 配置參數(shù)詳解
proxy_connect_timeout
作用:Nginx 與 upstream 建立連接的超時(shí)
建議:通常 1-3 秒足夠,過大只會(huì)拖慢失敗暴露時(shí)間
proxy_read_timeout
作用:Nginx 等待 upstream 返回響應(yīng)的時(shí)間
建議:按接口類型設(shè)置,不同接口單獨(dú)配置
keepalive
作用:upstream 長連接池大小
建議:按 QPS 和 upstream 并發(fā)能力估算,不要盲目拉滿
worker_connections
作用:單 worker 可處理的最大連接數(shù)
建議:結(jié)合worker_processes、FD 限制和長連接比例綜合評(píng)估
backlog
作用:監(jiān)聽套接字的已完成連接隊(duì)列長度
建議:高并發(fā)入口層保持較高值,并結(jié)合somaxconn一起調(diào)
C. 術(shù)語表
| 術(shù)語 | 英文 | 解釋 |
|---|---|---|
| 上游服務(wù) | upstream | Nginx 代理轉(zhuǎn)發(fā)到的后端服務(wù) |
| 連接拒絕 | connection refused | 目標(biāo)端口未監(jiān)聽或被拒絕建立連接 |
| 連接重置 | connection reset by peer | 對端主動(dòng)斷開已建立連接 |
| 監(jiān)聽隊(duì)列 | backlog | 等待應(yīng)用層accept的已完成連接隊(duì)列 |
| 長連接復(fù)用 | keepalive | 復(fù)用已建立連接,減少重復(fù)建連開銷 |
D. 內(nèi)核參數(shù)聯(lián)動(dòng)建議
Nginx 連接超時(shí)類問題,很多最后都要落到內(nèi)核參數(shù)上。入口層參數(shù)和 Linux TCP 參數(shù)最好配套看,不然前端調(diào)大了,后端隊(duì)列還是不夠,癥狀不會(huì)消失。
# 文件路徑:/etc/sysctl.d/99-nginx-net.conf net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 262144 net.core.netdev_max_backlog = 250000 net.ipv4.ip_local_port_range = 10240 65000 net.ipv4.tcp_fin_timeout = 15 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_syncookies = 1 fs.file-max = 2097152
應(yīng)用方法:
sudo sysctl --system sysctl net.core.somaxconn sysctl net.ipv4.tcp_max_syn_backlog
這些參數(shù)的使用邊界要記清楚:
somaxconn要和listen backlog一起看,只改一邊沒有意義
ip_local_port_range太小會(huì)導(dǎo)致本機(jī)發(fā)起的上游連接端口耗盡
tcp_fin_timeout和tcp_tw_reuse適合連接量大的反向代理層,但上線前要在測試環(huán)境驗(yàn)證
fs.file-max和進(jìn)程級(jí)nofile要一起調(diào),不然系統(tǒng)級(jí)夠了,worker 級(jí)還是會(huì)撞上限
-
內(nèi)核
+關(guān)注
關(guān)注
4文章
1470瀏覽量
42899 -
nginx
+關(guān)注
關(guān)注
0文章
187瀏覽量
13124
原文標(biāo)題:Nginx 常見故障排查手冊:502、504、連接超時(shí)逐個(gè)分析
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評(píng)論請先 登錄
顯卡常見故障維修
電源常見故障現(xiàn)象
直流穩(wěn)壓電源常見故障分析與排查
焊接機(jī)器人常見故障及排查
吉時(shí)利2400數(shù)字源表常見故障排查與校準(zhǔn)教程
云原生環(huán)境里Nginx的故障排查思路
Nginx常見故障案例總結(jié)
Keithley吉時(shí)利6511常見故障排查及解決方法
UPS電源常見故障維修全解析:從排查到修復(fù)的實(shí)戰(zhàn)指南
Nginx常見故障排查手冊
評(píng)論