max_fails与fail_timeout共同构成滑动时间窗口计数器,fail_timeout定义统计失败的时间范围(如30s内),max_fails设定该窗口内累计失败阈值(如3次),达阈值后节点被临时摘除fail_timeout时长;二者必须协同调整,孤立修改会导致误判或失效。

max_fails 不是“失败几次就永久下线”,而是和 fail_timeout 绑定的滑动窗口计数器——配错一个,另一个就失效。
max_fails 和 fail_timeout 必须成对调整,不能只改一个
这两个参数共同定义了一个「失败计数窗口」:Nginx 在最近 fail_timeout 秒内,只要累计失败次数达到 max_fails,就临时摘除节点。关键在于:fail_timeout 不是“摘除后等待多久恢复”,而是“用来统计失败的时长范围”;而节点真正被跳过的时长,也恰好是这个 fail_timeout 值。
常见误配:
- 只把
max_fails改成 10,但fail_timeout还是默认 10s → 高 QPS 下每秒失败率 1% 就会触发摘除,节点反复进出 down 状态 - 把
fail_timeout拉到 60s,但max_fails还是 1 → 单次超时就下线,且一停就是 60 秒,恢复太慢 - 设
max_fails=0→ 等价于禁用被动健康检查,节点永远不被自动摘除
不同业务类型对应的核心配置组合
没有万能值,只有匹配你后端响应节奏的值。重点看单次请求耗时分布和错误容忍度:
-
高敏感低流量接口(如支付回调、风控通知):
max_fails=1+fail_timeout=10s。首次失败即隔离,但必须配套proxy_next_upstream timeout http_502,否则偶发抖动也会被杀 -
常规 Web API(QPS 数百~数千,平均响应 max_fails=3 +
fail_timeout=30s。这是最稳的起点,能过滤掉 GC 暂停或瞬断导致的单点失败 -
高并发网关(QPS 万级+,失败天然更频繁):
max_fails=20+fail_timeout=10s。缩短统计窗口 + 提高容错阈值,避免毛刺引发震荡 -
慢响应服务(报表导出、大文件上传,单次可能耗时 40s+):
max_fails=2+fail_timeout=60s。防止一次真实慢请求就被计入多次失败
proxy_next_upstream 是 max_fails 生效的前提
max_fails 默认只统计 connect refused 和 connection timeout,不会把 502/503/504 当作失败——除非你显式启用它。
必须在 location 块中配置:
proxy_next_upstream error timeout http_500 http_502 http_503 http_504; proxy_next_upstream_tries 3; proxy_next_upstream_timeout 10s;
否则即使后端返回一堆 502,fails 计数器也不会动,max_fails 形同虚设。
注意:http_404 默认不计入失败(语义上不算故障),也不建议加;invalid_header 可按需加入,常见于后端协议异常。
节点恢复不是定时心跳,而是“首次新请求触发”
被标记为 down 的节点,在 fail_timeout 时间结束后,并不会自动发心跳探测。Nginx 是等**下一个新请求到达时**,才尝试往它发一次——成功则重新纳入轮询,失败则重置计时器。
这意味着:
- 如果流量稀疏,可能几十秒甚至几分钟都没人去“试”它,恢复延迟远超
fail_timeout - 当所有节点都 down 时,Nginx 会强制重试全部节点(包括刚被标记 down 的),这是唯一能绕过“静默等待”的兜底机制
- 如果你依赖快速恢复,就得搭配主动健康检查(如
health_check指令,仅 Nginx Plus 或带第三方模块的开源版支持)
最容易被忽略的一点:max_fails 的失败计数是「滑动窗口累加」,不是「固定周期清零」——两次失败之间夹着成功请求,仍会继续累加,直到窗口滑出最老那次失败。这决定了它对抖动的敏感度比想象中更高。











