Nginx中不存在“轮询调度算法的平滑重试机制”这一统一概念;轮询是请求分发策略,重试是故障转移行为,二者职责分离;平滑重试需通过proxy_next_upstream配合健康检查与合理参数协同实现。
Nginx 中并不存在“轮询调度算法的平滑重试机制”这个统一概念——轮询(round-robin)是请求分发策略,而重试(retry)是故障转移行为,二者职责分离、机制独立。真正需要配置的是:在轮询基础上,如何让失败请求“平滑地”切换到其他健康节点重试,这依赖 proxy_next_upstream 配合健康检查与合理参数协同实现。
proxy_next_upstream 是重试的核心开关它不改变轮询顺序,而是在某次转发失败后,主动跳过当前节点,按 upstream 当前可用列表继续轮询下一个节点。
关键配置示例:
upstream backend { server 192.168.1.10:8080 max_fails=3 fail_timeout=30s; server 192.168.1.11:8080 max_fails=3 fail_timeout=30s; server 192.168.1.12:8080 backup; # 故障兜底}location / { proxy_pass http://backend; proxy_next_upstream error timeout http_502 http_503 http_504 invalid_header; proxy_next_upstream_tries 3; proxy_next_upstream_timeout 10s;}
error timeout:覆盖网络层异常(建连失败、响应中断) http_502/503/504:覆盖后端崩溃、过载或上游网关超时,换节点成功率高 invalid_header:拦截“假存活”响应(如空响应体、缺失 Status 行) ⚠️ 不要加 http_404 或 http_500:前者是业务路径问题,后者多为逻辑错误,重试会放大风险。
没有健康检查,proxy_next_upstream 只是“失败→换一个再试”,可能连续命中已宕机节点。
必须为每个 server 显式配置:
max_fails=3:连续失败 3 次即标记为不可用 fail_timeout=30s:30 秒内不再调度该节点 这样,重试时实际参与轮询的节点已是实时健康的子集,切换才有意义。
更进一步可启用主动健康检查(需 OpenResty 或 Nginx Plus):
health_check interval=3 fails=2 passes=2;
比被动等待更快剔除故障节点,缩短重试窗口。
加权轮询(如 weight=3 和 weight=1)影响的是正常请求的分配比例,不影响重试路径。
重试始终按 upstream 当前可用节点的轮询顺序进行(非按权重重新计算),但会跳过已被 max_fails 标记为 down 的节点。
例如 upstream 有 A(weight=3)、B(weight=1)、C(weight=1),若 A 已被标记为 down,则重试只在 B 和 C 间轮询,此时 B:C = 1:1,而非 1:1 的原始权重比被临时“归一化”。
重试本质是重复发送请求,只有无副作用的操作才安全:
http_502 重试,可能导致重复下单、扣款、创建资源等严重问题 建议将非幂等接口单独路由,禁用重试,或仅限 error timeout 级别兜底。
不复杂但容易忽略。