zoukankan      html  css  js  c++  java
  • dubbo学习(八)负载均衡

    概述

    在上一节我们将集群的时候,最后的 invoker 又 负载均衡的 select 方法选出,我们先来看一下上一节设计到负载均衡的代码, AbstractClusterInvoker 类 :

       private Invoker<T> doSelect(LoadBalance loadbalance, Invocation invocation,
                                    List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
    
            if (CollectionUtils.isEmpty(invokers)) {
                return null;
            }
            if (invokers.size() == 1) {
                return invokers.get(0);
            }
    
            // 调用 loadbalance 的 select 方法
            Invoker<T> invoker = loadbalance.select(invokers, getUrl(), invocation);
    
            ...
        }     
    
    

    这里先给出几种负载均衡模式的实现优缺点 。

    1297993-20200303161933558-267203461.png

    我们来分析一下几种负载均衡实现过程。

    AbstractLoadBalance 父类分析

    public abstract class AbstractLoadBalance implements LoadBalance {
    
    
        /**
         * Calculate the weight according to the uptime proportion of warmup time
         * the new weight will be within 1(inclusive) to weight(inclusive)
         *
         * warmup : 预热时间
         *
         * @param uptime the uptime in milliseconds
         * @param warmup the warmup time in milliseconds
         * @param weight the weight of an invoker
         * @return weight which takes warmup into account
         */
        static int calculateWarmupWeight(int uptime, int warmup, int weight) {
            int ww = (int) ( uptime / ((float) warmup / weight));
            return ww < 1 ? 1 : (Math.min(ww, weight));
        }
    
        @Override
        public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {
            if (CollectionUtils.isEmpty(invokers)) {
                return null;
            }
            if (invokers.size() == 1) {
                return invokers.get(0);
            }
            return doSelect(invokers, url, invocation);
        }
    
        protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);
    
    
        /**
         * Get the weight of the invoker's invocation which takes warmup time into account
         * if the uptime is within the warmup time, the weight will be reduce proportionally
         * 
         * 
         * 这里计算权重的时候,核心就是 uptime/warmuptime 的占比,可以知道当开始启动的时候,uptime 较小占比小于是权重就小
         * 当启动久了占比就大了,权重自然就大了。
         *
         * @param invoker    the invoker
         * @param invocation the invocation of this invoker
         * @return 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 {
                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;
                        }
                        // 默认的预热时间是 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);
        }
    }
    
    

    RandomLoadBalance

        @Override
        protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
            // Number of invokers
            int length = invokers.size();
            // Every invoker has the same weight?
            boolean sameWeight = true;
            // the weight of every invokers
            int[] weights = new int[length];
            // the first invoker's weight
            int firstWeight = getWeight(invokers.get(0), invocation);
            weights[0] = firstWeight;
            // The sum of weights
            int totalWeight = firstWeight;
            for (int i = 1; i < length; i++) {
                int weight = getWeight(invokers.get(i), invocation);
                // save for later use
                weights[i] = weight;
                // Sum
                totalWeight += weight;
                if (sameWeight && weight != firstWeight) {
                    sameWeight = false;
                }
            }
            if (totalWeight > 0 && !sameWeight) {
                // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
                int offset = ThreadLocalRandom.current().nextInt(totalWeight);
                // Return a invoker based on the random value.
                // 循环让 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);
                    }
                }
            }
            // If all invokers have the same weight value or totalWeight=0, return evenly.
            return invokers.get(ThreadLocalRandom.current().nextInt(length));
        }
    

    总结

    其他类的分析就不再深入了,都是根据均衡算法得出某个 invoker .

    参考资料

    • http://dubbo.apache.org/zh-cn/docs/source_code_guide/loadbalance.html
  • 相关阅读:
    win10家庭版安装Docker for Windows
    docker镜像拉取速度过慢的解决
    解决docker: error pulling image configuration: Get https://registry-1.docker.io/v2/library/mysql/: TLS handshake timeout.
    ubuntu16.04下安装docker
    Ubuntu 16.04执行 sudo apt-get update非常慢解决方案
    [转载]MySQL存储过程详解  mysql 存储过程
    除非 Windows Activation Service (WAS)和万维网发布服务(W3SVC)均处于运行状态,
    windows资源管理器已经停止工作
    Shell脚本sqlldr导入数据压缩文件截断
    oracle 日常运维
  • 原文地址:https://www.cnblogs.com/Benjious/p/12720952.html
Copyright © 2011-2022 走看看