zoukankan      html  css  js  c++  java
  • dubbo源码分析1——负载均衡

      dubbo中涉及到的负载均衡算法只要有四种:Random LoadBalance(随机均衡算法)、RoundRobin LoadBalance(权重轮循均衡算法)、LeastAction LoadBalance(最少活跃调用数均衡算法)、ConsistentHash LoadBalance(一致性Hash均衡算法)。

      在dubbo中,首先定义了一个LoadBalance的接口。

    public interface LoadBalance {
    
        /**
         * select one invoker in list.
         *
         * @param invokers   invokers.
         * @param url        refer url
         * @param invocation invocation.
         * @return selected invoker.
         */
        @Adaptive("loadbalance")
        <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
    
    }
    

      这个接口中,只定义了一个select方法,用于在候选的invokers中选择一个invoker对象出来。

      首先有一个AbstractLoadBalance类来实现LoadBalance接口,重写了LoadBalance接口中唯一的select方法。

    public abstract class AbstractLoadBalance implements LoadBalance {
    
        static int calculateWarmupWeight(int uptime, int warmup, int weight) {
            int ww = (int) ((float) uptime / ((float) warmup / (float) weight));
            return ww < 1 ? 1 : (ww > weight ? weight : ww);
        }
    
        public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {
            if (invokers == null || invokers.size() == 0)
                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);
    
        protected int getWeight(Invoker<?> invoker, Invocation invocation) {
            int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
            if (weight > 0) {
                long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
                if (timestamp > 0L) {
                    int uptime = (int) (System.currentTimeMillis() - timestamp);
                    int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
                    if (uptime > 0 && uptime < warmup) {
                        weight = calculateWarmupWeight(uptime, warmup, weight);
                    }
                }
            }
            return weight;
        }
    
    }
    

      1.invoker的list中若0个则返回null,1个元素则直接返回,若多于否则调用抽象方法doSelect交给子类实现;

      2.通过公式(int) ( (float) uptime / ( (float) warmup / (float) weight ) )获取invoker的权重的方法;

      3.如果未设置权重或者权重值都一样,则直接调用random.nextInt()随机获得一个invoker;若设置了权重并且不一样,则在总权重中随机,分布在哪个invoker的分片上,则选择该invoker对象,实现了按照权重随机。

      四种不同的负载均衡算法分别为四个类,分别进行分析。

    1.Random LoadBalance(随机均衡算法)

    public class RandomLoadBalance extends AbstractLoadBalance {
    
        public static final String NAME = "random";
    
        private final Random random = new Random();
    
        protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
            int length = invokers.size(); // Number of invokers
            int totalWeight = 0; // The sum of weights
            boolean sameWeight = true; // Every invoker has the same weight?
            for (int i = 0; i < length; i++) {
                int weight = getWeight(invokers.get(i), invocation);
                totalWeight += weight; // Sum
                if (sameWeight && i > 0
                        && weight != getWeight(invokers.get(i - 1), invocation)) {
                    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 = random.nextInt(totalWeight);
                // Return a invoker based on the random value.
                for (int i = 0; i < length; i++) {
                    offset -= getWeight(invokers.get(i), invocation);
                    if (offset < 0) {
                        return invokers.get(i);
                    }
                }
            }
            // If all invokers have the same weight value or totalWeight=0, return evenly.
            return invokers.get(random.nextInt(length));
        }
    
    }

          1.计算总共的权重totalWeight;

      2.如果权重不同,则使用随机函数确认在总权重中的偏移值offset,得到调用的机器;

      3.如果权重相同,则直接调用随机函数确认机器。

    2.RoundRobin LoadBalance(权重轮循均衡算法)

    public class RoundRobinLoadBalance extends AbstractLoadBalance {
    
        public static final String NAME = "roundrobin";
    
        private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
    
        protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
            String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
            int length = invokers.size(); // Number of invokers
            int maxWeight = 0; // The maximum weight
            int minWeight = Integer.MAX_VALUE; // The minimum weight
            final LinkedHashMap<Invoker<T>, IntegerWrapper> invokerToWeightMap = new LinkedHashMap<Invoker<T>, IntegerWrapper>();
            int weightSum = 0;
            for (int i = 0; i < length; i++) {
                int weight = getWeight(invokers.get(i), invocation);
                maxWeight = Math.max(maxWeight, weight); // Choose the maximum weight
                minWeight = Math.min(minWeight, weight); // Choose the minimum weight
                if (weight > 0) {
                    invokerToWeightMap.put(invokers.get(i), new IntegerWrapper(weight));
                    weightSum += weight;
                }
            }
            AtomicPositiveInteger sequence = sequences.get(key);
            if (sequence == null) {
                sequences.putIfAbsent(key, new AtomicPositiveInteger());
                sequence = sequences.get(key);
            }
            int currentSequence = sequence.getAndIncrement();
            if (maxWeight > 0 && minWeight < maxWeight) {
                int mod = currentSequence % weightSum;
                for (int i = 0; i < maxWeight; i++) {
                    for (Map.Entry<Invoker<T>, IntegerWrapper> each : invokerToWeightMap.entrySet()) {
                        final Invoker<T> k = each.getKey();
                        final IntegerWrapper v = each.getValue();
                        if (mod == 0 && v.getValue() > 0) {
                            return k;
                        }
                        if (v.getValue() > 0) {
                            v.decrement();
                            mod--;
                        }
                    }
                }
            }
            // Round robin
            return invokers.get(currentSequence % length);
        }
    
        private static final class IntegerWrapper {
            private int value;
    
            public IntegerWrapper(int value) {
                this.value = value;
            }
    
            public int getValue() {
                return value;
            }
    
            public void setValue(int value) {
                this.value = value;
            }
    
            public void decrement() {
                this.value--;
            }
        }
    
    }

    3.LeastAction LoadBalance(最少活跃调用数均衡算法)

    4.ConsistentHash LoadBalance(一致性Hash均衡算法)

    最少活跃数

  • 相关阅读:
    wcf第3步之报文分析及原生调用
    IBatis 批量插入数据之SqlBulkCopy
    MVC前后端数据被编码
    log4Net控制台输出
    这可能是由于服务终结点绑定未使用 HTTP 协议造成的 .这还可能是由于服务器中止了 HTTP 请求上下文
    IBatis存储过程返回值
    路由学习2
    restClient访问SSL
    hibernate多对多关系配置
    hibernate 一对多操作(级联操作)
  • 原文地址:https://www.cnblogs.com/Mr24/p/8186614.html
Copyright © 2011-2022 走看看