dubbo 负载均衡算法实现的学习

随机数权重算法

假设一个服务service1 分布在一个含有4个节点(A, B, C, D)的集群上。 权重分别为1,2,3,4。那么一个请求service1 的 到 A,B,C,D 节点的概率为 10%,20%,30%,40%。
一个对于service1 的请求 会被随机分配一个数字。这个数字是A,B,C,D 节点权重之和范围类随机出来的。我们的例子中权重之和是10,所以随机数范围是【0,9】
假设随机出了数字 6, 那么选择的节点是D。原因是:6-1=5>0, 5-2=3>0, 3-3=0>=0, 0-4<0。原理是依次和各个权重相减,直到<0为止,找到D节点。

/**
 * 随机数权重算法
 */
public Node randomWeightAlgorithm() {
    List<Node> nodeList = new ArrayList<>();
    nodeList.add(new Node(1, 1));
    nodeList.add(new Node(2, 2));
    nodeList.add(new Node(3, 3));
    nodeList.add(new Node(4, 4));

    int len = nodeList.size();
    int totalWeight = 0;
    boolean sameWeight = true;
    for (int i = 0; i < len; i++) {
        int weight = nodeList.get(0).weight;
        totalWeight+=weight;
        if (sameWeight && i > 0 && weight != nodeList.get(i-1).weight) {
            // 节点权重都不相同
            sameWeight = false;
        }
    }
    if (totalWeight > 0 && !sameWeight) {
        int offset = ThreadLocalRandom.current().nextInt(totalWeight);
        for (Node aNodeList : nodeList) {
            offset -= aNodeList.weight;
            if (offset < 0) {
                return aNodeList;
            }
        }
    }
    // 如果节点权重相同, 则随机返回一个节点
    return nodeList.get(ThreadLocalRandom.current().nextInt(len));
}

基于权重的轮询算法

普通的轮询就是权重相同的情况。如果服务service1 部署在集群A,B,C,D四台机器上。那么第一个服务请求被路由到机器A,第二个请求被路由到机器B, 依次类推。
当4个节点权限不同时,维护一个map<服务标记位,权重计数器>。 每次请求过来,权重计数器+1。
每次请求过来,找出出最大,最小的权重。(权重计数器+1) % 最大权重, 得到这次请求的权重基准线。找出>权重基准线的节点们,再用当前权限基准线 % 这些节点的数量(Size) = 要选择的节点的下标。就可以获得选择的节点。

// <唯一标识接口的id, 权重计数器>
private final ConcurrentMap<Integer, AtomicPositiveInteger> sequences = new ConcurrentHashMap<>();

  /**
 * 基于权重的轮训调度算法
 */
public Node roundRobinLoadBalance() {
    // mock 4 个 节点
    List<Node> nodeList = new ArrayList<>();
    nodeList.add(new Node(1, 1));
    nodeList.add(new Node(2, 2));
    nodeList.add(new Node(3, 3));
    nodeList.add(new Node(4, 4));
    // 假设一个id = 5 标识一个唯一的接口
    int key = 5;
    int length = nodeList.size();
    int maxWeight = 0;
    int minWeight = Integer.MAX_VALUE;
    // 找出最大,最小权重值
    for (int i = 0; i< length; i++) {
        int weight = nodeList.get(i).weight;
        maxWeight = Math.max(maxWeight, weight);
        minWeight = Math.min(minWeight, weight);
    }
    // 4个节点的权重不同
    if (maxWeight > 0 && minWeight < maxWeight) {
        AtomicPositiveInteger weightSequence = sequences.get(key);
        if (weightSequence == null) {
            sequences.putIfAbsent(key, new AtomicPositiveInteger());
        }
        int currentWeight = weightSequence.getAndIncrement() % maxWeight;
        List<Node> nodesAfterSelect = new CopyOnWriteArrayList<>();
        // 筛选权重>当前权重的节点们
        for (Node node : nodeList) {
            if (node.weight > currentWeight) {
                nodesAfterSelect.add(node);
            }
        }
        int weightLength = nodesAfterSelect.size();
        if (weightLength == 1) {
            return nodesAfterSelect.get(0);
        }
        if (weightLength > 1) {
            return nodesAfterSelect.get(currentWeight % weightLength);
        }
    }
    // 四个节点权重相同
    AtomicPositiveInteger sequence =  sequences.get(key);
    if (sequence == null) {
        sequences.putIfAbsent(key, new AtomicPositiveInteger());
        sequence = sequences.get(key);
    }
    // 通过取模来轮训某个节点
    return nodeList.get(sequence.getAndIncrement() % length);
}

猜你喜欢

转载自blog.csdn.net/ZHANGYONGHAO604/article/details/81512555