dubbo源码分析第二十四篇一dubbo负载均衡一RandomLoadBalance一RoundRobinLoadBalance

dubbo源码分析第二十四篇一dubbo负载均衡一RandomLoadBalance一RoundRobinLoadBalance,第1张

dubbo源码分析第二十四篇一dubbo负载均衡一RandomLoadBalance一RoundRobinLoadBalance

文章目录

RandomLoadBalance加权随机RoundRobinLoadBalance加权轮询

源码分析

RandomLoadBalance加权随机

权重不同则加权随机权重相同则直接随机权重同最小活跃数一样,前10分钟预热阶段,权重从0到配置的weight随时间平滑增长

  protected  Invoker doSelect(List> invokers, URL url, Invocation invocation) {
       
        int length = invokers.size();
        boolean sameWeight = true;
        int[] weights = new int[length];
        int firstWeight = getWeight(invokers.get(0), invocation);
        weights[0] = firstWeight; 
        int totalWeight = firstWeight;
        for (int i = 1; i < length; i++) {
            获取权重
            int weight = getWeight(invokers.get(i), invocation);
            weights[i] = weight;
            获取总权重
            totalWeight += weight;
            判断是否存在权重不同
            if (sameWeight && weight != firstWeight) {
                sameWeight = false;
            }
        }
        存在加权不同
        if (totalWeight > 0 && !sameWeight) { 
            int offset = ThreadLocalRandom.current().nextInt(totalWeight);
            // 循环让 offset 数减去服务提供者权重值,当 offset 小于0时,返回相应的 Invoker。
            // 举例说明一下,我们有 servers = [A, B, C],weights = [5, 3, 2],offset = 7。
            // 第一次循环,offset - 5 = 2 > 0,即 offset > 5,
            // 表明其不会落在服务器 A 对应的区间上。
            // 第二次循环,offset - 3 = -1 < 0,即 5 < offset < 8,
            // 表明其会落在服务器 B 对应的区间上
            for (int i = 0; i < length; i++) {
                offset -= weights[i];
                if (offset < 0) {
                    return invokers.get(i);
                }
            }
        }
         加权全部相同
        return invokers.get(ThreadLocalRandom.current().nextInt(length));
    }

RoundRobinLoadBalance加权轮询
轮询逻辑: 根据[权重]增加所有Invoker的[轮询值] ([轮询值] += [权重])
[轮询值]大于当前最大值,作为本次被选中Invoker
[轮询值] 减少所有Invoker[权重] ([轮询值] -= total[权重])
权重: weight  轮询值: current
Invoker1Invoker2Invoker3选择结果weight100100100current000current第一轮开始100100100current第一轮结果-200100100选择Invoker1 轮询值 = 100-100*3current第二轮开始-100200200current第二轮结果-100-100200选择Invoker2 200-100*3current第三轮开始00300current第三轮结果000选择Invoker3 300-100*3

一个周期后,所有的Invoker的current[轮询值]基本回归,如果权重相同,回归至0

源码分析
protected  Invoker doSelect(List> invokers, URL url, Invocation invocation) {
    获取当前调用方法的 加权轮询元信息(WeightedRoundRobin)
    String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
    {methodWeightMap: key->当前方法,val-> 所有Invoker对应的轮询信息}   {map,当前所有的invoker key -> 当前Invoker的唯一id ,val -> 当前的轮询信息 }
    ConcurrentMap map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>());
    int totalWeight = 0;
    long maxCurrent = Long.MIN_VALUE;
    long now = System.currentTimeMillis();
    Invoker selectedInvoker = null;
    WeightedRoundRobin selectedWRR = null;
    所有的Invoker遍历处理
    for (Invoker invoker : invokers) {
        获取当前invoker的唯一标识
        String identifyString = invoker.getUrl().toIdentityString();
        获取每一个Invoker的权重
        int weight = getWeight(invoker, invocation);
        给每一个轮询信息设置权重
        WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> {
            WeightedRoundRobin wrr = new WeightedRoundRobin();
            wrr.setWeight(weight);
            return wrr;
        });
        if (weight != weightedRoundRobin.getWeight()) {
            weightedRoundRobin.setWeight(weight);
        }
        每次增加自己的当前轮询值为权重weight
        long cur = weightedRoundRobin.increaseCurrent();
        weightedRoundRobin.setLastUpdate(now);

        找出当前轮询值最小的Invoker
        if (cur > maxCurrent) {
            maxCurrent = cur;
            selectedInvoker = invoker;
            selectedWRR = weightedRoundRobin;
        }
        totalWeight += weight;
    }


    if (invokers.size() != map.size()) {
        如果一个WeightedRoundRobin 60秒都没有参与过for循环里的轮询处理,则移除该Invoker
        就要借助methodWeightMap记忆轮询的信息,又清除了Invoker变动残存的轮询信息
        map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);
    }
    if (selectedInvoker != null) {
        每次被选中后,当前的轮询值减去所有Invoker的轮询值  从而达到轮询效果
        selectedWRR.sel(totalWeight);
        return selectedInvoker;
    }
    永远不会走到,兜底逻辑
    return invokers.get(0);
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5710938.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存