SWLC 平滑加权最小连接算法是什么?Nginx 负载均衡策略选型与配置
“加权轮询”“最少连接”这些词天天挂在嘴上,但生产环境里真正该用的是平滑加权轮询(WRR)和平滑加权最少连接(SWLC)。前者的“平滑”解决了流量突刺,后者的“加权”解决了机器性能不均。本文把两者的算法推导和 Nginx 配置一起讲清楚。

一、普通轮询与加权轮询的问题
假设三台后端权重为 5、1、1。朴素加权轮询会连续把 5 个请求打到 A 机,再打 B、C 各一次——这就是“突发式分配”,短时间内容量小的机器被连续冲击,容易瞬时打满。平滑加权轮询(Smooth Weighted Round-Robin)的目标是:既让长期比例严格等于权重,又让每一次选择都尽量分散。
二、平滑加权轮询的算法推导
Nginx 给每个节点维护两个值:weight(配置权重)与 current_weight(动态累计值),另有 effective_weight 用于被动健康检查时降权。每轮选择流程:
- 遍历所有存活节点,令
current_weight += weight; - 选出
current_weight最大的节点作为本次目标; - 被选中者
current_weight -= total_weight(所有权重之和); - 若本次请求失败,
effective_weight -= fail_factor(默认 6),并按fail_timeout(默认 10s)标记不可用;成功则effective_weight += 1,直至回到weight。
以 weight 5/1/1(总和 7)为例,选择序列是 A A B A C A D…,实际前 7 次为 A、A、B、A、C、A、(第 7 轮回到起点),比例长期精确为 5:1:1,且 A 的两两之间被 B、C 隔开。这套逻辑在 Nginx 源码 ngx_http_upstream_round_robin.c 的 ngx_http_upstream_rr_peer_get_weight 相关实现里,可对照阅读。
三、最小连接:按“当前忙碌程度”分配
WRR 只看权重,不看请求耗时差异。如果同一份权重下有的接口 10ms、有的 800ms,静态权重就会失真。最小连接(Least Connections)的思路是选当前活动连接数最少的后端:
upstream back {
least_conn;
server 10.0.0.11:8080 weight=5 max_conns=200;
server 10.0.0.12:8080 weight=1 max_conns=100;
server 10.0.0.13:8080 weight=1;
keepalive 64;
}
需要注意 least_conn 统计的是该 worker 进程视角的连接数(多 worker 下不是全局值);max_conns(1.17.5 起引入)是硬上限,超过后按 limit_rate 之外的逻辑排队或直接返回 502,用它兜底比调权重更稳。
四、SWLC:加权 + 最小连接的组合
SWLC(Smooth Weighted Least Connections)把两者合一:选择依据是 连接数 / 权重,即“按容量归一化后的繁忙度”,值最小者优先。这就是 Tengine(阿里开源,https://tengine.taobao.org/ )里 least_conn ... weight 与 ip_hash 之外常用的 swls/ewma 模块思路:
upstream back {
least_conn; # Tengine 的 swls 需重新编译模块
server 10.0.0.11:8080 weight=5;
server 10.0.0.12:8080 weight=1;
}
更精确的是按响应时延加权的 ewma(Exponentially Weighted Moving Average,Tengine 提供),它把“平均时延”也计入选择,适合接口耗时波动大的网关。
要点:官方 Nginx 开源版只有 round-robin(本身就是平滑加权)、ip_hash、least_conn、hash(带 consistent)、random 几种;真正的 SWLC/ewma 要用 Nginx Plus(velocity、least_time)或 Tengine/OpenResty 的第三方模块。选型前务必确认手上版本,配置里写错算法名会直接 unknown parameter 启动失败。
五、其它常用策略与适用场景
ip_hash:按客户端 IP 前 3 段哈希,会话粘滞友好;但经过大型运营商 NAT 或公司出口时会出现严重倾斜,且后端扩缩容会打散映射(除非加consistent)。hash $request_uri consistent:一致性哈希(ketama),适合后端是缓存节点的架构,扩缩容时只迁移一小部分 key。random least_conn:先随机挑两个再取连接少的,超大集群(几百台)下比全量扫描省 CPU。sticky cookie(Nginx Plus):应用级会话保持,比 IP 哈希可靠。
配套的失败转移参数别漏:max_fails=3 fail_timeout=30s 控制被动摘除;proxy_next_upstream error timeout http_502 http_504 决定什么错误要重试到下一台;proxy_next_upstream_tries 2 防止重试放大雪崩。
六、验证与压测方法
- 把后端各机器返回自己的主机名,用
for i in $(seq 1 100); do curl -s http://gw/whoami; echo; done | sort | uniq -c统计分布,实测比例与权重比对(权重 5:1:1 应约得 71/14/14)。 nginx -T打印生效配置,确认 upstream 真的被proxy_pass http://back;引用(很多人改了半天发现用的是另一台 server 块)。- 长连接场景要让
proxy_http_version 1.1;+proxy_set_header Connection "";+keepalive N;三者齐全,否则 upstream 连接不复用,least_conn 的统计意义会失真。
七、常见问题 FAQ
问:weight=0 是什么意思?
答:把该节点标记为 backup 之外的“不参与”,常配合 backup 用作冷备;weight=0 也不能配 max_conns=0 混淆(后者表示不限制)。
问:为什么我配了权重,实际流量比例不对?
答:三个常见原因——(1) least_conn 本身就按连接数而非权重轮转;(2) 有请求耗时差异;(3) 客户端用了 HTTP/2 多路复用,一个连接承载很多请求,连接数失去意义。这时应改用 random least_conn 或带权重的 EWMA。
问:平滑加权轮询会不会造成“某台机器一直被选”?
答:不会连续过多。算法保证任意连续 total_weight 次内,每个节点被选次数恰等于其权重,这是“平滑”的数学含义。
实践建议:中小集群、请求耗时均匀 → 默认 WRR 即可;耗时差异大或有长任务 → least_conn; heterogeneous 机型混部 → 加权版最小连接(SWLC);后端是缓存分片 → hash ... consistent。
生产内容,同时打通搜索引擎(SEO)与AI搜索引擎(GEO)流量入口的软件! 点击进入365建站器 »
