要真正看清集群中各节点的健康分布,必须依赖 $upstream_status 而非 $status,它记录后端真实响应及重试全过程;需自定义日志格式并启用 upstream_log,结合 awk 按节点与错误码聚合分析,注意重试干扰,并可为各节点生成独立日志实现精细化可观测。

要真正看清集群中各节点的健康分布,不能只看 Nginx 返回给客户端的 $status(比如全是 200),而必须依赖 $upstream_status——它记录的是后端真实返回的状态码,包括重试过程中的每一次响应,是诊断抖动、定位故障节点的核心依据。
必须先记录有意义的 upstream_status
Nginx 默认 access_log 不包含上游状态。需在 http 块中明确定义日志格式:
log_format upstream_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'$upstream_status $upstream_addr $upstream_response_time '
'"$http_referer" "$http_user_agent"';
再在 server 或 location 块中启用:
access_log /var/log/nginx/upstream.log upstream_log;
重启 Nginx 后,每行日志就会类似:
192.168.1.100 - - [12/May/2026:15:30:22 +0000] "GET /api/order HTTP/1.1" 200 342 200 10.0.2.5:8080 0.037 "https://app.com" "curl/7.68"
注意:若发生重试,$upstream_status 可能为 "504,502,200",$upstream_addr 可能为 "10.0.2.5:8080, 10.0.2.6:8080"——这两个字段都要一起分析。
按节点+错误码聚合,识别异常源头
健康分布的关键是“谁在错、错得多不多”。用 awk 快速统计:
-
查各节点返回的 4xx/5xx 分布(例如哪台机器 500 高发):
awk '{print $7, $8}' /var/log/nginx/upstream.log | grep "^[45]" | sort | uniq -c | sort -nr(假设
$7是$upstream_status,$8是$upstream_addr;字段序号需根据实际日志格式校准) -
定位高频失败的后端地址:
awk '$7 ~ /^[45]/ {print $8}' /var/log/nginx/upstream.log | sort | uniq -c | sort -nr | head -10 特别注意重试干扰:若某行含
"500 10.0.2.5:8080,10.0.2.6:8080",说明第一次失败后重试了另一节点——两个地址都应纳入排查,不能只盯第一个。
结合 status 与 upstream_status 判定故障类型
-
$status == 502且$upstream_status == 502→ 后端主动返回 502,查其自身日志(如应用崩溃、数据库连不上) -
$status == 502但$upstream_status == "-"或为空 → CLB/Nginx 未收到任何响应,常见于后端端口未监听、安全组拦截(如阿里云 CLB 要求放行100.64.0.0/10)、连接被 reset -
$status == 200但$upstream_status含"504,200"或"502,200"→ 后端存在抖动,靠重试兜底,P99 延迟可能已恶化,需检查proxy_read_timeout是否过短,或后端慢查询
进阶:为每个节点生成独立日志,实现长期可观测
仅靠全局日志难以区分节点行为。推荐用 map 映射地址为 ID,并动态写入节点专属日志:
map $upstream_addr $backend_id {
default "unknown";
"10.0.2.5:8080" "node-a";
"10.0.2.6:8080" "node-b";
}
log_format node_log '$remote_addr [$time_local] "$request" '
'$status $upstream_status $upstream_response_time $backend_id';
access_log /var/log/nginx/backend/$backend_id-access.log node_log;
这样就能对 node-a-access.log 单独做错误率计算、P95 响应时间分析、缓存命中率统计等,真正落到每个实例。
不复杂但容易忽略











