要准确追踪后端服务响应状态码分布,必须记录并分析 $upstream_status 而非 $status,需自定义日志格式、启用 upstream_log,结合字段提取、聚合统计与异常模式识别实现精准故障定位。

要准确追踪后端服务响应状态码分布,关键不是看 Nginx 返回给客户端的 $status(比如 502、503),而是捕获它从上游真实收到的 $upstream_status。这个值才能反映后端服务本身是否健康、返回了什么错误。
必须启用并正确记录 $upstream_status
Nginx 默认日志不包含上游状态码。需在 http 块中明确定义日志格式:
log_format upstream_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'upstream_addr:$upstream_addr '
'upstream_status:$upstream_status '
'upstream_response_time:$upstream_response_time '
'request_time:$request_time';
然后在对应 location 或 server 中启用:
access_log /var/log/nginx/upstream.log upstream_log;
注意:$upstream_status 在连接失败、超时或未转发时会显示为 -,这是正常行为,可用来识别“无响应”类故障。
按后端实例+状态码聚合分析
单看总错误率没意义,要定位到具体哪台机器、哪个接口出问题:
-
统计每台后端返回的 4xx/5xx 分布(便于发现某节点异常):
awk '$10 ~ /^[45]/ {print $9, $10}' /var/log/nginx/upstream.log | sort | uniq -c | sort -nr(假设
是upstream_addr,是upstream_status;字段位置请按实际 log_format 核对) -
查看高频失败的后端地址(快速圈定问题节点):
awk '$10 ~ /^[45]/ {print $9}' /var/log/nginx/upstream.log | sort | uniq -c | sort -nr | head -10
区分“真失败”和“假健康”
有些请求看似成功($status == 200),但上游其实返回了 500,却被 Nginx 用 error_page 或 proxy_intercept_errors on 拦截并替换成自定义页面——此时 $upstream_status 可能为空或被覆盖。
确保:
- 关闭
proxy_intercept_errors on(保持默认off) - 避免用
error_page 500 =200 /fallback.html这类重写,改用proxy_next_upstream触发重试 - 启用
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;,让失败能重试,同时保留最终成功节点的$upstream_status
结合时间维度做异常检测
状态码突增比绝对值更有预警价值。例如:
-
upstream_status中500在 1 分钟内上升 300%,可能表示某服务崩溃 - 大量
-出现在同一upstream_addr,说明该节点已失联(非超时,是连接拒绝或网络中断) -
upstream_response_time > 3s且upstream_status == 200,提示后端慢但没挂,需查资源瓶颈
可用 tail -f 实时管道分析,或接入 Prometheus + Grafana 做长期趋势监控。
不复杂但容易忽略











