最近在看dubbo的一些代码,看到cluster层的负载均衡这块,目前支持一致性hash的ConsistentHashLoadBalance,
最少活跃数的LeastActiveLoadBalance,随机RandomLoadBalance,轮询的RoundRobinLoadBalance。
其中看到轮询这块有一个平滑轮询算法的算法


主要思路就是每个节点会有一个权重weight,每次让他的current = current + weight,获取最新的权重值,
同时累加每个节点的最新权重值current, totalWeight = totalWeight + current。
current值最大的节点为本次需要调用的节点,需要把本次选取节点的current = current - totalWeight。



public static void main(String[] args) {
    Map<String, WeightRounbin> rounbinMap = Lists.newArrayList(
            new WeightRounbin("10.0.0.1", 1),
            new WeightRounbin("10.0.0.2", 2),
            new WeightRounbin("10.0.0.3", 3))
            .stream().collect(Collectors.toMap(WeightRounbin::getIp, x -> x));
    testRound(12, rounbinMap);
}

private static void testRound(int n, Map<String, WeightRounbin> rounbinMap) {
    for (int i = 0; i < n; i++) {
        int MAX_WEIGHT = Integer.MIN_VALUE, totalWeight = 0;
        WeightRounbin select = null;
        for (WeightRounbin rounbin : rounbinMap.values()) {
            int weight = rounbin.getWeight();
            if (weight > MAX_WEIGHT) {
                select = rounbin;
                MAX_WEIGHT = weight;
            }
            totalWeight += weight;
        }
        if (select != null) {
            select.resetNextWeight(totalWeight);
            System.out.println(String.format("本次选择的ip: %s, 被选中次数: %s", select.getIp(), select.getCount()));
        }

    }
}


public static class WeightRounbin {

    private String ip;

    private int weight;

    private AtomicInteger selectCount = new AtomicInteger(0);

    private AtomicInteger current = new AtomicInteger(0);

    public WeightRounbin(String ip, int weight) {
        this.ip = ip;
        this.weight = weight;
    }

    public String getIp() {
        return ip;
    }

    public int getWeight() {
        return current.addAndGet(weight);
    }

    public void resetNextWeight(int totalWeight) {
        current.addAndGet(-totalWeight);
        selectCount.incrementAndGet();
    }

    public int getCount() {
        return selectCount.get();
    }
}


调用12次的话,有6次会落到权重为3的节点,4次落到权重为2的节点,2次落到权重为1的节点。
得到的结果会穿插的,权重大的节点也不会被频繁的调用。

本次选择的ip: 10.0.0.3, 被选中次数: 1
本次选择的ip: 10.0.0.2, 被选中次数: 1
本次选择的ip: 10.0.0.3, 被选中次数: 2
本次选择的ip: 10.0.0.1, 被选中次数: 1
本次选择的ip: 10.0.0.2, 被选中次数: 2
本次选择的ip: 10.0.0.3, 被选中次数: 3
本次选择的ip: 10.0.0.3, 被选中次数: 4
本次选择的ip: 10.0.0.2, 被选中次数: 3
本次选择的ip: 10.0.0.3, 被选中次数: 5
本次选择的ip: 10.0.0.1, 被选中次数: 2
本次选择的ip: 10.0.0.2, 被选中次数: 4
本次选择的ip: 10.0.0.3, 被选中次数: 6