权重轮询通过累计权重与取模计算实现O(1)空间调度,避免重复存储;用servers[]、weights[]数组和AtomicInteger维护currentIndex,按权重比例循环返回服务器。

权重轮询(Weighted Round Robin)是一种常见的负载均衡策略,它根据服务器的权重值按比例分配请求。在 Java 中,不依赖第三方框架,仅用数组就能高效实现——核心在于用累计权重替代重复存储,避免内存浪费,同时保证分配结果可预测、可复用。
理解权重轮询的核心逻辑
假设有三台服务器:A(权重3)、B(权重2)、C(权重=1),理想分配序列应为 A,A,A,B,B,C(共6次循环),即每个服务器被选中的频次与其权重严格成正比。但直接构造长度为总权重的数组(如长度6的字符串数组)在权重很大时(如 1000、5000)会浪费内存。更优做法是:维护当前指针 + 累计权重判断,用 O(1) 空间完成 O(1) 单次调度。
用两个数组实现轻量级权重轮询
定义两个平行数组:
- servers[]:存储服务器标识(如 IP 或名称)
- weights[]:对应位置的整数权重(必须 ≥ 1)
再维护一个全局变量 currentIndex(初始为 0)和一个预计算的 totalWeight(所有权重之和)。每次调用 nextServer() 时:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
- 对
currentIndex取模totalWeight,得到本轮偏移量pos - 遍历
weights[],累加权重直到累计和 >pos,返回对应下标的服务器 - 将
currentIndex自增 1
例如:weights = [3,2,1] → totalWeight = 6;当 currentIndex = 4,pos = 4 % 6 = 4;累加:3(A)→ 小于 4;+2=5(B)→ 大于 4 → 返回 B。
代码实现(无状态、线程安全建议)
以下为简洁可运行示例(使用 AtomicInteger 保障多线程下的 currentIndex 安全):
public class WeightedRoundRobin {
private final String[] servers;
private final int[] weights;
private final int totalWeight;
private final AtomicInteger currentIndex = new AtomicInteger(0);
public WeightedRoundRobin(String[] servers, int[] weights) {
if (servers.length == 0 || servers.length != weights.length) {
throw new IllegalArgumentException("Servers and weights must be non-empty and same length");
}
for (int w : weights) {
if (w < 1) throw new IllegalArgumentException("Weight must be >= 1");
}
this.servers = servers;
this.weights = weights;
this.totalWeight = Arrays.stream(weights).sum();
}
public String nextServer() {
int pos = currentIndex.getAndIncrement() % totalWeight;
int sum = 0;
for (int i = 0; i < weights.length; i++) {
sum += weights[i];
if (pos < sum) {
return servers[i];
}
}
return servers[0]; // fallback (should never reach here)
}
}
// 使用示例:
// String[] s = {"192.168.1.10", "192.168.1.11", "192.168.1.12"};
// int[] w = {3, 2, 1};
// WeightedRoundRobin lb = new WeightedRoundRobin(s, w);
// for (int i = 0; i < 12; i++) System.out.println(lb.nextServer());
注意事项与优化方向
该实现时间复杂度为 O(n),n 是服务器数量,适用于几十台以内的场景。若服务器数极多(如数百),可预构建前缀和数组 + 二分查找,将单次调度降至 O(log n);若需支持运行时权重动态变更,应加锁或改用 CAS 更新整个权重快照;另外,真实生产中建议配合健康检查剔除失效节点,避免流量打到宕机机器。

















