轮询本身不包含重试逻辑,仅负责首次按序分发请求;重试由proxy_next_upstream独立控制,目标为当前健康节点池中的任意成员,非严格轮询顺序,需显式配置避免流量倾斜。

轮询模式本身不包含重试逻辑,重试是独立于负载均衡算法的额外机制。两者叠加时容易引发非预期行为,尤其是对 POST 等非幂等请求。
轮询分发只管“第一次往哪送”
默认轮询(Round Robin)按顺序把每个新请求分配给下一台 upstream 服务器,不关心后端是否响应、是否超时、是否返回错误。它只做一次决策,不回退、不重选、不补偿。
- 三台后端 A/B/C,第1次到A、第2次到B、第3次到C、第4次又回到A
- 若A在第1次请求时超时或返回502,轮询计数器仍会前进——第2次请求照常发给B,不会因为A失败就再试一次A
- 也就是说:轮询负责“初始分发”,失败后交由 proxy_next_upstream 决定是否重试、重试谁
重试不是轮询的延续,而是另起一套选择逻辑
proxy_next_upstream 触发重试时,并不会严格按轮询顺序找“下一个”,而是从 upstream 列表中筛选出当前健康的节点,再从中选取一台——这个过程可能跳过已失败节点,也可能重复选到同一台(尤其当健康检查未及时剔除异常节点时)。
- 例如:A超时 → Nginx 尝试重试,默认启用 timeout 选项 → 从剩余健康节点 B/C 中选一个,不保证是B
- 如果B也慢,且 proxy_next_upstream_tries 设为2,第二次重试可能又落到B,或回到A(若A已恢复健康)
- 关键点:重试目标 ≠ 轮询序列中的“下一个”,而是“当前可用节点池中的任一成员”
必须显式控制重试范围,否则轮询+重试=流量倾斜
默认配置下,proxy_next_upstream 包含 timeout,而 proxy_next_upstream_tries 和 proxy_next_upstream_timeout 均为0(不限),这会导致单个请求可能打遍所有后端,彻底破坏轮询的均匀性。
- 禁用非幂等请求的重试:proxy_next_upstream error;(去掉 timeout)
- 限制重试次数与总耗时:proxy_next_upstream_tries 2; proxy_next_upstream_timeout 8s;
- 确保健康检查参数统一:所有 server 行的 max_fails、fail_timeout 必须一致,否则某台节点可能被过早剔除或长期滞留,干扰轮询节奏
验证轮询是否真正生效,得看 $upstream_addr 日志,而非重试后的结果
想确认轮询是否按序分发,不能看最终成功响应来自哪台——因为重试会让多个请求最终落在同一台;要盯住每条请求首次分发的目标地址。
- 配置 log_format 含 $upstream_addr,记录每次实际转发目标
- 连续发起请求,观察日志是否呈现 A→B→C→A 的固定循环
- 若发现某台频繁出现在“首次分发”列,说明 upstream 配置有干扰项(如残留 ip_hash、weight 不为1、健康状态不一致)











