max_fails和fail_timeout共同构成动态滑动失败窗口:fail_timeout定义统计时间窗口长度,max_fails设定该窗口内允许的最大失败次数,达限则节点被标记为down并隔离fail_timeout秒后由新请求试探恢复。

max_fails 和 fail_timeout 是 Nginx 被动健康检查的核心参数,它们不单独起作用,而是共同构成一个**动态滑动失败窗口**,用于判断后端节点是否真的故障,而不是误判一次网络抖动或瞬时超时。
它们的真实协作逻辑
这两个参数必须成对配置,行为是联动的:
- fail_timeout 定义时间窗口起点:每次发生失败(如连接拒绝、超时、502 等),Nginx 就以该时刻为起点,开启一个持续 fail_timeout 秒的统计窗口
- max_fails 是该窗口内允许的失败累计次数:只要在这个滑动窗口里失败达到 max_fails 次,节点立即被标记为 down
- 成功请求不会清零计数,但会重置窗口起点:比如 max_fails=3、fail_timeout=30s,第 2 秒失败一次,第 25 秒又失败,第 38 秒再失败——后两次落在同一窗口(从第 25 秒起算),计数达 3,节点被摘除
- 节点被标记为 down 后,持续隔离 fail_timeout 秒:到期后不会自动恢复,而是由下一个新请求去试探;若成功,则重新纳入轮询
常见场景下的推荐组合
参数值不能拍脑袋定,要贴合你的服务特征:
- 高频轻量接口(如健康检查、用户信息查询):max_fails=3,fail_timeout=15s —— 过滤单次毛刺,又避免过早剔除
- 中低频但关键接口(如支付回调、风控校验):max_fails=1,fail_timeout=10s —— 零容忍,但需配合 proxy_next_upstream 显式启用 http_502/http_504
- 已知周期性延迟服务(如每 30 秒一次 GC):max_fails=2,fail_timeout=60s —— 拉长窗口,避开规律性慢响应
必须同步配置的关键项
只设 max_fails 和 fail_timeout 不够,Nginx 默认只把“连不上”算失败,而很多闪断表现为“连上了但返回 502”或“卡住不回包”。所以务必补全:
- 显式启用错误码判定:在 location 或 upstream 外层加 proxy_next_upstream error timeout http_502 http_504
- 限制重试放大风险:proxy_next_upstream_tries 2(最多再试 1 次)、proxy_next_upstream_timeout 10s(总耗时超时即止)
- 匹配业务超时节奏:proxy_read_timeout 建议设为单次正常响应耗时的 1.5~2 倍,再据此调整 retry timeout
验证是否生效的小技巧
改完别只 nginx -t,要实测行为是否符合预期:
- 用 tc 或 iptables 在后端机器上模拟随机丢包(比如 15%),观察 error.log 中 upstream failed 日志是否集中在某节点,且之后出现一段静默期(对应 fail_timeout)
- 查日志命令示例:grep "upstream.*failed" /var/log/nginx/error.log | tail -20
- 手动 curl 触发请求,看是否在节点被标记 down 后,流量自动切到其他节点,且 30 秒(或你设的 fail_timeout)后首次请求能试探恢复











