平滑加权轮询的Java实现

205 阅读1分钟

记得Nginx用这个实现。

算法步骤:

  1. 初始化:

    • 设置每个节点的权重(weight)。
    • 初始化每个节点的当前权重(current_weight)为0。
  2. 选择过程: a. 对所有节点的当前权重加上其初始权重。 b. 选择当前权重最大的节点。 c. 将被选中节点的当前权重减去所有节点的权重总和。 d. 返回选中的节点。

  3. 重复步骤2进行下一次选择。


最大公约数(GCD)的作用:

计算GCD的主要目的是优化权重,使算法更加高效。

如果原始权重是 {10, 20, 30},它们的GCD是10。优化后的权重变成 {1, 2, 3}。

  1. 最大值(max)的作用:

计算最大值主要用于确定算法的循环周期和初始化当前权重。

权重 {1, 2, 3},最大值是3。这意味着在3次选择后,算法会完成一个完整的周期。

public class WeightedRoundRobin {
    private int[] weights;
    private int[] currentWeights;
    private int maxWeight;
    private int currentIndex;
    private int totalWeight;

    public WeightedRoundRobin(int[] weights) {
        int gcdWeight = gcd(weights);
        this.weights = new int[weights.length];
        for (int i = 0; i < weights.length; i++) {
            this.weights[i] = weights[i] / gcdWeight;
        }
        this.currentWeights = new int[weights.length];
        this.maxWeight = max(this.weights);
        this.currentIndex = -1;
        this.totalWeight = 0;
        for (int weight : this.weights) {
            this.totalWeight += weight;
        }
    }

    private int gcd(int[] numbers) {
        int result = numbers[0];
        for (int number : numbers) {
            result = gcd(result, number);
        }
        return result;
    }

    private int gcd(int a, int b) {
        while (b != 0) {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    private int max(int[] numbers) {
        int max = numbers[0];
        for (int number : numbers) {
            if (number > max) {
                max = number;
            }
        }
        return max;
    }

    public int getNextIndex() {
        while (true) {
            currentIndex = (currentIndex + 1) % weights.length;
            if (currentIndex == 0) {
                for (int i = 0; i < currentWeights.length; i++) {
                    currentWeights[i] += weights[i];
                }
            }
            if (currentWeights[currentIndex] >= 1) {
                currentWeights[currentIndex] -= totalWeight;
                return currentIndex;
            }
        }
    }