在 nginx 中,默认的加权轮询(weighted round-robin)算法无法自动感知后端服务器的响应延迟,导致慢请求会阻塞后续请求的处理。要解决这个问题,必须引入健康检查机制,通过主动探测或被动剔除来隔离响应过慢的后端节点,确保流量只分配给健康的服务器。

如何配置被动健康检查以剔除慢速节点
使用 `max_fails` 和 `fail_timeout` 参数可以实现被动的健康检查。当 Nginx 发现某个后端在指定时间内连续失败次数超过阈值时,会将该节点标记为不可用,并在超时时间内不再向其发送请求。

upstream backend {
server 192.168.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 weight=3 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 weight=2 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_connect_timeout 5s;
proxy_read_timeout 10s;
}
}
在上述配置中,如果 192.168.1.10 在 30 秒内连续返回错误(如 502、504 或连接超时),Nginx 会在接下来的 30 秒内忽略该节点。这能有效防止慢速节点拖垮整个集群的响应速度。需要注意的是,被动检查依赖于实际请求的失败,因此对于偶尔出现的慢请求可能不够灵敏。
如何实现主动健康检查以提前发现慢节点
被动检查存在滞后性,更优的方案是使用第三方模块(如 nginx_upstream_check_module)进行主动健康检查。该模块允许 Nginx 定期向所有后端发送探测请求,根据探测结果动态调整权重或剔除节点。

# 需要在编译 Nginx 时添加 --add-module=/path/to/nginx_upstream_check_module
upstream backend {
server 192.168.1.10:8080 weight=5;
server 192.168.1.11:8080 weight=3;
server 192.168.1.12:8080 weight=2;
# 每 10 秒检查一次,超时 2 秒视为失败,连续失败 3 次剔除
check interval=10000 rise=2 fall=3 timeout=2000 type=http;
check_http_send "HEAD /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
主动检查通过定期发送 HEAD 请求到 /health 接口来判断后端状态。如果后端响应时间超过 2 秒或返回非 2xx/3xx 状态码,计数器会增加。连续失败 3 次后,该节点将被暂时从上游列表中移除。这种方式能更早地发现并隔离慢速节点,避免用户请求直接打到故障节点上。
当后端响应时间超过 proxy_read_timeout 时会发生什么
当后端处理时间超过 proxy_read_timeout 设定的值时,Nginx 会主动断开与后端的连接,并向客户端返回 504 Gateway Time-out 错误。这一行为会触发被动健康检查中的失败计数,可能导致节点被临时剔除。
在之前的配置示例中,proxy_read_timeout 设置为 10 秒。如果 192.168.1.10 处理一个请求耗时 11 秒,Nginx 将终止该连接并记录一次失败。由于 max_fails 设为 3,如果此类情况在短时间内频繁发生,该节点将在 30 秒内被暂停服务。这种机制确保了单个慢请求不会无限期占用资源,同时通过健康检查保护了集群的整体稳定性。











