dubbo RandomLoadBalance的一点优化

时间:2024-03-20 11:25:51

背景

在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 weighted random 基于权重的随机负载均衡策略。并且,默认权重相同。当权重相同和不同时,随机逻辑不同。这样就需要判断权重是否相同。

权重不同

假设集群中存在四个服务a、b、c、d,权重分别为10、20、25、15。随机逻辑如下:

  1. 通过加和算出总权重,总权重为10+20+25+15=70。
  2. 基于总权重生成随机数,随机数需满足0<=randomValue<70。
  3. 按序排列得出各个服务对应区间,服务a,b,c,d对应区间分别为[0, 10),[10, 30),[30, 55),[55, 70)。
  4. 判断随机数在哪个区间,就负载到对应的服务。

代码逻辑如下:

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

public class LoadBalanceDemo {

    public static void main(String[] args) {
        List<Serv> l = new ArrayList<>(4);
        Serv a = new Serv("a", 10);
        l.add(a);
        Serv b = new Serv("b", 20);
        l.add(b);
        Serv c = new Serv("c", 25);
        l.add(c);
        Serv d = new Serv("d", 15);
        l.add(d);
        Serv res = null;
        int totalWeight = 0;
        int[] weights = new int[4];
        for (int i = 0; i < l.size(); i++) {
            Serv serv = l.get(i);
            totalWeight += serv.weight;
            weights[i] = totalWeight;
        }
        Random random = new Random();
        int randomVal = random.nextInt(totalWeight);
        for (int i = 0; i < weights.length; i++) {
            int weight = weights[i];
            if (randomVal < weight) {
                res = l.get(i);
            }
        }
        System.out.println(res.name);
    }

    static class Serv {

        String name;
        int weight;

        public Serv(String name, int weight) {
            this.name = name;
            this.weight = weight;
        }
    }
}

权重相同

权重相同时,只需要按照服务个数进行随机即可。代码逻辑如下:

int randomVal = new Random().nextInt(servs.size());

重头戏

如何判断权重是否相同呢?

方法一:获取任一服务的权重与其他服务权重一一作比较。如果有不同的,那权重一定不同。否则则权重相同。代码逻辑如下

public static void main(String[] args) {
    List<Serv> l = new ArrayList<>(4);
    Serv a = new Serv("a", 10);
    l.add(a);
    Serv b = new Serv("b", 20);
    l.add(b);
    Serv c = new Serv("c", 25);
    l.add(c);
    Serv d = new Serv("d", 15);
    l.add(d);
    boolean sameWeight = true;
    Serv baseServ = l.get(0);
    for (int i = 1; i < l.size(); i++) {
        Serv serv = l.get(i);
        if (baseServ.weight != serv.weight) {
            sameWeight = false;         
        }
    }
    System.out.println(sameWeight);
}

这种方法的优点是直观,缺点是存在硬编码。

方法二:按序判断单一权重和总权重的倍数关系。因为我们是通过加和的方式算出总权重,当权重相同时,那第一个服务的权重就等于当前累加值,第二个服务的权重等于当前累加值的二分之一,以此类推。这样,我们就能判断权重是否相同了。代码逻辑如下:

public static void main(String[] args) {
    List<Serv> l = new ArrayList<>(4);
    Serv a = new Serv("a", 10);
    l.add(a);
    Serv b = new Serv("b", 20);
    l.add(b);
    Serv c = new Serv("c", 25);
    l.add(c);
    Serv d = new Serv("d", 15);
    l.add(d);
    boolean sameWeight = true;
    int totalWeight = 0;
    for (int i = 0; i < l.size(); i++) {
        Serv serv = l.get(i);
        if (serv.weight * i != totalWeight) {
            sameWeight = false;
        }
        totalWeight += serv.weight;
    }
    System.out.println(sameWeight);
}