Dubbo 负载均衡源码 - 最少活跃数

Posted by jiangydev on January 4, 2018

[TOC]

LeastActiveLoadBalance(最少活跃数)

根据统计收到请求时各提供者已有的请求数,在此基础上再考虑服务器权重值,使请求处理慢、性能相对不佳的提供者收到更少的请求。

引用 Alibaba 开源项目 Dubbo 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcStatus;

import java.util.List;
import java.util.Random;

public class LeastActiveLoadBalance extends AbstractLoadBalance {

    public static final String NAME = "leastactive";

    private final Random random = new Random();

    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        int length = invokers.size(); // invoker数量
        int leastActive = -1; // invoker最少活跃的值
        int leastCount = 0; // 有相同最少活跃值的invoker数量 (leastActive)
        int[] leastIndexs = new int[length]; // 有相同最少活跃值的invoker索引 (leastActive)
        int totalWeight = 0; // 权重值总和
        int firstWeight = 0; // 初始化值, 用来比较
        boolean sameWeight = true; // 是否每个invoker有相同的权重值?
        for (int i = 0; i < length; i++) {
            Invoker<T> invoker = invokers.get(i);
            int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // 激活数量
            int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); // 权重
            if (leastActive == -1 || active < leastActive) { // 重新开始, 当找到有一个更小最少活跃值的invoker时
                leastActive = active; // 记录当前最少活跃值
                leastCount = 1; // 重设 leastCount, 基于当前 leastCount 重新计数
                leastIndexs[0] = i; // Reset
                totalWeight = weight; // Reset
                firstWeight = weight; // 记录第一个invoker权重
                sameWeight = true; // Reset, every invoker has the same weight value?
            } else if (active == leastActive) { // 如果当前invoker的活跃值等于 leaseActive, then accumulating.
                leastIndexs[leastCount++] = i; // Record index number of this invoker
                totalWeight += weight; // Add this invoker's weight to totalWeight.
                // If every invoker has the same weight?
                if (sameWeight && i > 0
                        && weight != firstWeight) {
                    sameWeight = false;
                }
            }
        }
        // assert(leastCount > 0)
        if (leastCount == 1) {
            // 如果准确得到仅有一个invoker有最少活跃值, 直接返回这个invoker.
            return invokers.get(leastIndexs[0]);
        }
        if (!sameWeight && totalWeight > 0) {
            // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
            int offsetWeight = random.nextInt(totalWeight);
            // Return a invoker based on the random value.
            for (int i = 0; i < leastCount; i++) {
                int leastIndex = leastIndexs[i];
                offsetWeight -= getWeight(invokers.get(leastIndex), invocation);
                if (offsetWeight <= 0)
                    return invokers.get(leastIndex);
            }
        }
        // 如果所有的invoker有相同的权重值或 totalWeight=0, return evenly.
        return invokers.get(leastIndexs[random.nextInt(leastCount)]);
    }
}

举例

假设有服务器集合(服务器名:其权重值:活跃值):A(S0:1:2, S1:5:4, S2:5:3, S3:1:2, S4:3:2),权重值不同,通过遍历invokers,找出最小活跃值服务器集合:B(S0:1:2, S3:1:2, S4:3:2),活跃值均为2,然后通过 RandomLoadBalance(基于权重的随机负载均衡算法)得到最终的invoker(S0,S3的概率为1/5,S3的概率为3/5)。