Nginx 的 fail_timeout 不控制单次请求超时
Nginx 的 fail_timeout 和 max_fails 用于后端失败判定,不能相除得到单请求超时。按连接、发送和读取阶段配置时限,并区分重试与后端选择。
在 upstream 中写了 max_fails=3 fail_timeout=120s,不能据此认为单次请求会在 120 / 3 = 40 秒后超时。把 fail_timeout 调大或调小,也不会直接改变连接后端、发送请求或等待响应的时限。
这里讨论 Nginx 的 HTTP proxy_pass 代理和被动失败判定。FastCGI 等模块有自己的超时指令,不能把下面的 proxy_* 配置直接用于它们。
失败统计与请求等待分开配置
max_fails 与 fail_timeout 决定何时暂时停止选择一个后端:在指定时间范围内累计达到失败次数,便把该后端视为不可用,持续时间也由 fail_timeout 指定。这里的秒数不是每次请求的时间预算,次数也不是同一请求必定重试的次数。
单次通信要按阶段判断。连接后端用 proxy_connect_timeout;向后端写请求用 proxy_send_timeout;从后端读响应用 proxy_read_timeout。后两项限制相邻写入或读取之间的等待,并非整个请求或响应必须在该时限内传完。因此,持续有数据流动的长响应可以超过一个读取超时周期。
先查看失败请求对应的错误日志,区分尚未连接、正在发送请求,还是等待响应。随后核对真正命中的 location 和它继承的配置。只看到浏览器最终报错,无法判断该调哪个阶段;另一个代理层或客户端先结束请求,也不会因为调整本层失败窗口而恢复。
把阶段超时放在实际代理位置
下面是合入现有配置的示例片段,不是可覆盖整个站点的配置文件。两个地址和端口需要替换为实际后端;原站点的监听、TLS、认证与必要代理头继续保留。示例值只是说明各参数的位置,应根据业务允许的等待时间调整。
# 放在已有 http 上下文中
upstream api_backend {
server 192.0.2.10:8080 max_fails=3 fail_timeout=120s;
server 192.0.2.11:8080 max_fails=3 fail_timeout=120s;
}
# 放在已有 server 上下文中
location /api/ {
proxy_pass http://api_backend;
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 40s;
}
这时 40s 来自显式读取超时,与 120s / 3 没有关系。proxy_pass 没有附加 URI,示例保留 /api/ 路径;若原配置有路径替换,不要在调整时限时顺手改变它。
保存原配置,使用部署中实际的 Nginx 二进制和配置路径执行 nginx -t,通过后按原部署方式重载。这里不应同时缩短全部站点的时限。过短会切断合法的慢请求,过长会延长故障等待;后端数据库锁、应用阻塞等问题也不会由延长超时本身修复。
不要用请求次数直接推算后端何时被摘除
HTTP 代理的失败统计还受 proxy_next_upstream 规则影响。通信错误、超时和无效响应头会被计为失败;某些 HTTP 状态码只有在该指令中列出才计入,403 和 404 则不计入失败次数。因此“三个请求返回错误”不一定满足 max_fails=3。
若 upstream 实际只有一个后端,Nginx 会忽略这里的 max_fails 和 fail_timeout,不会据此把唯一后端判为不可用。一个域名可能解析出多个地址,不能只数配置中的 server 行来判断后端数量。
同一请求转给另一后端还受是否已经向客户端发送响应等条件限制。不要为凑出预期重试次数便启用非幂等请求重试:写入请求可能已经在后端生效,再发一次会重复操作。失败窗口、重试策略和业务幂等性应分别核对。
分别验证等待时限和后端选择
在隔离测试环境中,用已知会延迟返回的只读接口观察实际失败阶段和等待时间,确认修改的代理位置生效。若数据持续到达,不能用总下载时长超过 proxy_read_timeout 判定配置无效。
再结合每个后端的请求记录检查失败后的选择行为,不要把前端的总响应时间直接当作某一次后端等待时间。存在重试时,一个前端请求可能包含多次后端尝试。
若正常请求开始被过早中断,恢复保存的超时配置,重新检查并重载,再核对正常流量。恢复等待时间不代表后端性能已经恢复;仍需保留失败阶段和后端日志,继续处理导致请求迟迟无法完成的实际原因。


