dubbo源码分析第二十三篇一dubbo负载均衡-LeastActiveLoadBalance与预热机制

LeastActiveLoadBalance

  • 通过ActiveLimitFilter设置每个Invoker方法的活跃数,方法调用前+1,调用后-1
  • 获取活跃数最小的Invoker
  • 存在多个最小活跃数相同Invoker,根据权重配置随机获取
  • 存在多个最小活跃数相同Invoker,权重全部相同,随机获取
    在这里插入图片描述

源码分析

  • 根据Invoker信息计算最小活跃数Invoker
  • 根据最小活跃数数量,判断直接获取Invoker,加权随机获取Invoker,还是普通随机
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
    int length = invokers.size();
    所有调用者中最小活跃数
    int leastActive = -1;
    最小活跃数相同的Invoker数量
    int leastCount = 0;
    int[] leastIndexes = new int[length];
    int[] weights = new int[length];
    所有最不活跃的调用者的预热权重的总和
    int totalWeight = 0;
    第一个最不活跃的调用者的权重
    int firstWeight = 0;
    
    boolean sameWeight = true;
    根据Invoker的活跃数计算最小活跃数
    for (int i = 0; i < length; i++) {
        Invoker<T> invoker = invokers.get(i);
        获取当前url下的方法对应的活跃数,活跃数通过filter机制设置
        int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
        默认权重100,当启动时间小于预热时间[启动时间/预热时间]*100
        int afterWarmup = getWeight(invoker, invocation);
        每个Invoker的权重
        weights[i] = afterWarmup;
        if (leastActive == -1 || active < leastActive) {
        	第一个Invoker的最小权重或者出现新的最小权重Invoker
            leastActive = active;
            // Reset the number of least active invokers
            leastCount = 1;
            // Put the first least active invoker first in leastIndexes
            leastIndexes[0] = i;
            // Reset totalWeight
            totalWeight = afterWarmup;
            // Record the weight the first least active invoker
            firstWeight = afterWarmup;
            
            sameWeight = true;
           
        } else if (active == leastActive) {
             出现最小活跃数和已经统计的最小活跃数相同
            leastIndexes[leastCount++] = i;
            累计总权重
            totalWeight += afterWarmup;
            存在权重不同 则使用step-2 b 加权随机
            if (sameWeight && afterWarmup != firstWeight) {
                sameWeight = false;
            }
        }
    }

    step-2: 获取Invoker
	a 最小权重的Invoker数量相同的只有一个
    if (leastCount == 1) {
        return invokers.get(leastIndexes[0]);
    }
    b 最小权重的Invoker数量相同有多个 并且权重不相同
    if (!sameWeight && totalWeight > 0) {
        随机一个值 
        int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
        for (int i = 0; i < leastCount; i++) {
            int leastIndex = leastIndexes[i];
            判断随机的权重在不在当前加权权重范围
            offsetWeight -= weights[leastIndex];
            if (offsetWeight < 0) {
                return invokers.get(leastIndex);
            }
        }
    }
    c 权重全部相同或者总权重为0,直接随机获取
    return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);
}

预热机制

  • 默认启动服务的前10分钟称为预热期
  • 这10分钟的权重并非配置的weight值,而是(now-start)/10分钟*weight
  • 目的是为了减小对刚启动的机器的调用
int getWeight(Invoker<?> invoker, Invocation invocation) {
        int weight;
        URL url = invoker.getUrl();
        // Multiple registry scenario, load balance among multiple registries.
        if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) {
            weight = url.getParameter(REGISTRY_KEY + "." + WEIGHT_KEY, DEFAULT_WEIGHT);
        } else {
            // 从 url 中获取权重 weight 配置值 默认权重100
            weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
            if (weight > 0) {
                // 获取服务提供者启动时间戳
                long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L);
                if (timestamp > 0L) {
//                    计算服务提供者运行时长
                    long uptime = System.currentTimeMillis() - timestamp;

                    if (uptime < 0) {
                        return 1;
                    }
                    // 如果服务运行时间小于预热时间,则重新计算服务权重,即降权
                    // warmup默认10分钟
                    int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
                    if (uptime > 0 && uptime < warmup) {
                        weight = calculateWarmupWeight((int)uptime, warmup, weight);
                    }
                }
            }
        }
        return Math.max(weight, 0);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值