max_fails与fail_timeout共同定义滑动时间窗口内的失败容忍度,仅在fail_timeout秒内累计达max_fails次失败才触发节点摘除;默认仅connect refused和timeout计入失败,http错误需proxy_next_upstream显式配置才生效。

max_fails 不是“失败几次就永久下线”,它只在 fail_timeout 时间窗口内连续计数,且必须配合 proxy_next_upstream 才会真正触发失败累加——不配,等于白设。
max_fails 和 fail_timeout 是一对绑定参数,不能单独调
它们共同定义一个滑动时间窗口内的失败容忍度。Nginx 不是按“总失败次数”统计,而是看“最近 fail_timeout 秒内是否累计达到 max_fails 次失败”。关键细节:
- 失败不是清零重计,而是滚动窗口:若
fail_timeout=30s,T₀ 出现第 1 次失败,T₁(T₀+25s)再失败,fails=2;T₂(T₁+25s)又失败,此时 T₀ 已超窗,但 T₁、T₂ 仍在窗内,fails=3 → 触发摘除 - 摘除后节点状态重置:被标记为 down 的瞬间,
fails归零,新计数从首次恢复请求开始 - 设
max_fails=0等价于禁用被动检查;设过大(如 50)会导致故障节点长期滞留,失去保护意义
proxy_next_upstream 决定哪些错误能计入 fails
默认情况下,Nginx 只把连接拒绝(connect refused)和连接超时(timeout)算作失败;502/503/504 等 HTTP 错误默认不触发计数,哪怕返回满屏 502,max_fails 也不会涨。
必须显式启用对应状态码的重试,才能让它们参与失败判定:
- 在
location块中写:proxy_next_upstream error timeout http_500 http_502 http_503 http_504; -
error包含底层 I/O 错误,timeout涵盖 connect/read/send 超时 - 注意:
http_404默认不计入失败(除非业务明确需将其视为异常),且不建议加入,否则正常缺失资源会误杀节点 - 搭配
proxy_next_upstream_tries 3;和proxy_next_upstream_timeout 10s;控制重试边界,避免用户卡顿
不同业务类型的真实配置差异
没有万能值,只有匹配流量节奏和响应特征的组合:
-
高敏感低频接口(如支付回调、风控通知):
max_fails=1+fail_timeout=10s。单次 502 或超时即隔离,但务必开启proxy_next_upstream timeout http_502;,并确认后端健康检查端点稳定,否则抖动易误判 -
常规 Web API(QPS 数百~数千):
max_fails=3+fail_timeout=30s。覆盖常见 GC 暂停、瞬断、偶发 502,是多数团队可直接落地的基准线 -
高并发网关(QPS 万级+):
max_fails=15–20+fail_timeout=10s。缩短窗口+提高阈值,防止单个慢请求或毛刺反复触发摘除震荡 -
慢响应服务(报表导出、大文件上传):
max_fails=2+fail_timeout=60s。避免一次 48s 请求刚返回就被记为 timeout,拉低失败密度;同时需同步调大proxy_read_timeout 120s;
节点自动恢复不是定时心跳,而是“懒探测”
被摘除的节点不会在 fail_timeout 到点那一刻自动回归,而是等到下一个新请求到达时,Nginx 才向它发一次探测请求:
- 如果该请求成功,节点立刻回到轮询池;失败则继续 down,等待下一次请求再试
- 这意味着低流量时段,一个节点可能 down 超过
fail_timeout很久才恢复——比如fail_timeout=30s,但每分钟才来 1 个请求,实际恢复延迟可达 90s - 极端情况:所有主节点都 down 时,Nginx 会强制重试全部节点(包括刚被标记 down 的),这是唯一不依赖“新请求触发”的恢复路径
- 若需更及时恢复,必须引入主动健康检查(
health_check指令,仅 Nginx Plus 或 openresty 支持)
最容易被忽略的是:fail_timeout 既是“失败统计窗口”,也是“节点隔离时长”,两个语义共用一个数值。业务越不稳定,越要拉长这个时间窗;但拉长后,恢复延迟也变长——这本身就是权衡,不是靠调参能绕开的。











