需自定义 access_log 格式添加 $upstream_status 等变量,并调高 error_log 级别至 warn 以上,启用 proxy_next_upstream 和 proxy_intercept_errors,必要时用 tcpdump 或 debug 日志深入排查。

在 Nginx 故障转移(failover)场景中,日志里只显示 upstream timed out 或 upstream refused,却看不到具体 HTTP 状态码(如 502、503、504)或后端真实错误响应体,说明 Nginx 默认日志格式未捕获 upstream 响应细节,或错误阶段未被记录。
确认日志格式是否包含 upstream 状态与响应头
Nginx 默认的 log_format(如 combined)不记录 upstream 返回的状态码和响应头。需显式添加变量:
-
$upstream_status:记录 upstream server 实际返回的 HTTP 状态码(如 502/503/504),多个 upstream 时用逗号分隔 -
$upstream_http_x_debug_code(或其他自定义 header):若后端主动返回调试信息,可通过$upstream_http_*捕获 -
$upstream_addr和$upstream_response_time:辅助定位是哪个节点、耗时多少出的问题
示例自定义日志格式:
log_format upstream_detail '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$upstream_addr $upstream_status '
'$upstream_response_time $request_time '
'"$upstream_http_x_backend_info"';检查 error_log 级别是否足够捕获 upstream 错误细节
仅靠 access_log 不足以看到连接失败、SSL 握手异常、DNS 解析失败等底层问题。需确保 error_log 级别为 warn 或更高(如 error、crit):
-
error_log /var/log/nginx/error.log warn;—— 可捕获connect() failed、no live upstreams、ssl handshake failed等关键信息 - 避免设为
notice或更低,否则很多 upstream 异常会被静默忽略 - 若使用 stream 模块做 TCP/UDP 转发,需单独配置
stream { error_log ...; }
验证 upstream 配置是否启用健康检查与详细错误传递
默认情况下,Nginx 在遇到 upstream 错误时会尝试下一个 server,但可能跳过记录原始错误。需确认:
- 使用
proxy_next_upstream error timeout http_502 http_503 http_504;显式声明哪些错误触发重试,这样对应状态才会被$upstream_status记录 - 开启
proxy_intercept_errors on;后,Nginx 才会把 5xx 响应交给自定义 error_page 处理,否则直接透传并可能丢失上下文 - 若后端返回非标准状态码(如 499、599),需在
proxy_next_upstream中显式添加,否则不视为可重试错误
抓包或启用 debug 日志定位“看不见”的错误源头
当 access_log 和 error_log 仍无足够线索时,需深入协议层:
- 临时开启 debug 日志:
error_log /var/log/nginx/error.log debug;(注意磁盘空间和性能影响),可看到 upstream 连接建立、SSL 握手、header 解析全过程 - 用
tcpdump抓取 Nginx 与 upstream 之间流量:tcpdump -i any port 8080 -w upstream.pcap,过滤分析响应包内容 - 在 upstream server 侧检查其访问日志与错误日志,确认是否返回了预期状态码或提前断连


















