Nginx 默认不记录重试过程,仅在最终失败时记502/504;需开启debug日志、配置$upstream_addr等变量写入access_log,并结合proxy_next_upstream生效验证与抓包确认重试行为。

故障转移日志里缺少重试原因记录,本质是 Nginx 默认不把重试决策过程写入日志——它只在最终失败时记一次错误(如 502/504),而中间的“尝试下一个 upstream”动作是静默发生的。要看到重试原因,得主动开启更细粒度的日志输出,并结合上下文交叉验证。
确认 proxy_next_upstream 和 retry 相关配置是否生效
Nginx 是否执行重试,取决于 proxy_next_upstream 指令是否包含对应状态码或超时类型,且该指令必须出现在能影响代理行为的位置(如 location 或 upstream 块内)。常见疏漏包括:
- 配置了
proxy_next_upstream error timeout,但没加http_502,导致后端返回 502 时不重试,也就无重试日志可查 - 指令写在 server 块顶层,而非 location 或 upstream 内,Nginx 忽略该配置
- upstream 中设置了
max_fails=0或fail_timeout=0,实际禁用了健康检查与自动摘除,重试逻辑被绕过
启用详细 upstream 日志,捕获每次重试动作
默认 access_log 和 error_log 都不会记录“第几次重试”“换到了哪台服务器”这类信息。需显式开启调试级日志或使用变量打点:
- 在 error_log 指令中提高级别:
error_log /var/log/nginx/error.log debug;(仅临时开启,生产慎用;需编译时含 --with-debug) - 用
$upstream_addr和$upstream_response_time记入 access_log:log_format upstream_detail '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr" "$upstream_response_time" "$upstream_http_x_backend";'—— 可看出请求最终落到哪台后端、耗时多少、是否发生地址切换 - 配合
proxy_intercept_errors on;+ 自定义 error_page,把 502/504 重定向到带参数的诊断页,间接标记重试路径
从 error.log 中识别“隐性重试失败”的线索
即使没有明确“retried”字样,以下日志模式强烈暗示重试已发生但未成功:
-
[error] ... upstream timed out (110: Connection timed out) while reading response header from upstream, client: ..., server: ..., request: "...", upstream: "http://backend1"→ 后续若出现同一请求指向backend2的类似报错,说明已重试 -
[error] no live upstreams while connecting to upstream→ 所有 upstream 节点均被标记为不可用(因连续失败触发健康检查摘除),说明重试已穷尽所有节点 - access_log 中同一请求 ID(如通过
$request_id)在极短时间内出现多次 502,且$upstream_addr字段值不同
验证重试逻辑是否真被触发的实操方法
不要依赖日志“有没有写”,而是用可控方式验证行为本身:
- 临时配置一个双节点 upstream,其中第一个节点用 iptables 拦截响应:
iptables -I INPUT -p tcp --dport 8080 -j DROP,第二个节点正常;观察是否自动切到第二节点并返回成功 - 用 curl 加
-v并配合tcpdump -i lo port 8080抓包,确认客户端是否只发一次请求,而 Nginx 是否向多个后端发起了连接 - 在 upstream 块中添加
slow_start=30s和down标记,人为制造节点状态变化,再触发请求,看 error_log 是否出现upstream server temporarily disabled类提示


















