项目仓库: https://github.com/gnosek/nginx-upstream-fair
已编译源: https://deb.ksyaki.com/nginx/
Nginx 内置的 upstream 负载均衡可以解决“把请求分给哪些后端”的问题,但默认策略对后端当前忙闲程度的感知有限。round robin 主要按顺序分配,权重只改变分配比例;当某个后端已经积压较多请求时,它仍可能继续收到新请求。
nginx-upstream-fair 用来解决这个问题。它会跟踪每个 upstream peer 当前正在处理的请求数量,并优先把新请求分配给更空闲的后端。当前维护版本基于 Debian libnginx-mod-http-upstream-fair,并应用了动态模块、OpenSSL 1.1+ 和 Nginx 1.11.6+ 兼容补丁。
与上游版本的差异
上游 a18b409 已经包含基础的忙闲调度、no_rr、weight_mode 和共享内存配置。当前维护版本在这个基础上继续做了这些改动:
应用 Debian 兼容补丁,支持动态模块、OpenSSL 1.1+ 和 Nginx 1.11.6+。
增加与 nginx-healthcheck-module 的可选联动,可以在选择后端前过滤主动健康检查失败的 peer。
将 peer 和主备分组状态拆分到独立模块,并加强主组、backup 组的调度边界。
修复请求计数和 free 生命周期,避免计数、tried 位图、失败回报或 SSL session 归属到错误的组。
必要计数和选路规则不再依赖
--with-debug,reload 生命周期也改为通过 Nginx 原生配置提交回调发布。
当前维护版本支持
按后端当前忙闲程度分配请求
默认调度、
no_rr、weight_mode=idle和weight_mode=peak主组和 backup 组调度
与 nginx-healthcheck-module 联动,跳过主动健康检查失败的后端
静态 down、主动 down、被动失败冷却和请求 tried 状态过滤
静态模块和动态模块构建
共享内存计数和安全的 reload 生命周期
编译安装
首先下载 Nginx 源码和模块源码:
git clone https://github.com/nginx/nginx.git
git clone https://github.com/Akvicor/nginx-upstream-fair.git
cd nginx
git checkout release-1.26.3静态编译
./auto/configure --add-module=../nginx-upstream-fair
make
make install如果需要动态模块,可以改用:
./auto/configure --add-dynamic-module=../nginx-upstream-fair
make
make install动态模块还需要在 Nginx 配置中通过 load_module 加载生成的 .so 文件。动态构建只提供 fair-only 功能;如果需要 check 主动健康检查联动,请使用下文与 nginx-healthcheck-module 的共同静态构建方式。
基础配置
最简单的配置只需要在 upstream 中启用 fair:
upstream backend {
fair;
server 127.0.0.1:5000;
server 127.0.0.1:5001;
server 127.0.0.1:5002;
}
server {
listen 8080;
location / {
proxy_pass http://backend;
}
}启用后,模块会根据 peer 当前的在用请求数、历史分配情况和权重选择后端。正在处理请求较多的后端会少分到新请求,空闲后端会优先获得新请求。
调度模式
完整指令格式:
fair [no_rr] [weight_mode=idle|weight_mode=peak];默认模式会综合考虑当前在用请求、请求分配历史和权重。只要存在空闲候选,模块会优先选择空闲候选;没有空闲候选时,其余合格候选继续参与 busy 评分。
no_rr 控制既有轮转游标策略,可以和两种 weight_mode 组合使用。
weight_mode=idle
upstream backend {
fair weight_mode=idle;
server 127.0.0.1:5000 weight=1;
server 127.0.0.1:5001 weight=2;
}idle 模式在选择空闲后端时,把 weight 作为当前在用请求的参考界限。超过参考界限的节点仍可能进入 busy 选择,不会因为暂时较忙就永久退出调度。配合 no_rr 时,会继续沿用对已轻载节点的既有偏好。
这个模式适合希望尽量让后端保持空闲余量的场景。
weight_mode=peak
upstream backend {
fair weight_mode=peak;
server 127.0.0.1:5000 weight=4;
server 127.0.0.1:5001 weight=8;
server 127.0.0.1:5002 backup;
}peak 模式把 weight 当作多节点并发容量上限。主组容量都达到上限时,如果配置了 backup 组,请求可以进入 backup 组。
如果只有一个真实节点且没有 backup,模块保留原有的单节点特例,避免因为容量判断导致唯一后端不可用。
主组和 Backup 组
fair 支持 Nginx upstream 的主备模型:
upstream backend {
fair;
server 127.0.0.1:5000 weight=4;
server 127.0.0.1:5001 weight=4;
server 127.0.0.1:5002 backup;
}每个新请求先从主组选择。只有主组没有合格候选时,请求才会进入 backup 组。已经进入 backup 组的请求会按照原生请求生命周期继续在该组重试;主组恢复后,新请求会重新优先进入主组。
配置中至少要有一个主节点。主节点可以配置为静态 down,但如果 upstream 中只有 backup 节点,配置会加载失败。
与主动健康检查联动
fair 本身负责忙闲调度,主动健康检查由 nginx-healthcheck-module 提供。两个模块共同静态编译后,可以在 fair upstream 中配置 check:
upstream backend {
fair;
server 127.0.0.1:5000 weight=2 max_fails=2 fail_timeout=10s;
server 127.0.0.1:5001;
server 127.0.0.1:5002 backup;
check type=tcp interval=3000 timeout=1000 rise=2 fall=5;
}共同构建方式:
git clone https://github.com/nginx/nginx.git
git clone https://github.com/Akvicor/nginx-healthcheck-module.git
git clone https://github.com/Akvicor/nginx-upstream-fair.git
cd nginx
git checkout release-1.26.3
git apply ../nginx-healthcheck-module/nginx_healthcheck_for_nginx_1.26+.patch
./auto/configure \
--with-stream \
--add-module=../nginx-healthcheck-module \
--add-module=../nginx-upstream-fair
make配置了 check 后,显式 upstream 内主组和 backup 组的非静态 down 地址都会注册主动健康检查。主动检查失败的 peer 会在 fair 选择阶段被过滤;主动恢复为 up 后,也仍需要满足 Nginx 被动失败冷却状态,才会重新接收业务请求。
如果配置了检查但注册失败,当前配置会被拒绝加载。这可以避免 Nginx 以“看起来配置了健康检查,但实际没有生效”的状态运行。
状态过滤语义
fair 选择后端时会分别考虑以下状态:
静态 down:配置中明确标记为 down 的 peer 不参与选择。
主动 down:健康检查判定异常的 peer 不参与选择。
被动失败冷却:业务请求失败触发的 Nginx 原生冷却仍然生效。
tried:当前请求已经尝试过的 peer 不会在同一个重试周期中重复选择。
这些状态是独立判断的。主动健康检查恢复为 up 只会更新主动健康状态,不会直接清除业务请求造成的被动失败冷却。
共享内存和 Reload
fair 使用共享内存保存 peer 计数。可以通过下面的指令调整共享区大小:
http {
upstream_fair_shm_size 8m;
}该指令位于 http 层级。默认值和最小值都是 8 个系统页,配置值会按页对齐。修改已有共享区大小需要重启 Nginx,而不是只执行 reload。
配置加载失败时,旧配置和原有 worker 会继续工作。加载成功后,新 worker 使用新配置,旧 worker 按 Nginx 原生优雅退出规则完成已有请求。
使用建议
只想按忙闲分配请求时,直接使用默认
fair;。希望 weight 表示空闲参考界限时使用
weight_mode=idle。希望 weight 表示并发容量上限时使用
weight_mode=peak。有 backup 组时,确认主组至少保留一个主节点。
需要主动剔除故障后端时,与 nginx-healthcheck-module 共同静态构建。
修改
upstream_fair_shm_size后使用完整重启,而不是 reload。构建后先执行
nginx -t,再用实际 upstream 流量验证调度效果。