dubbo源码分析-负载均衡算法

来源:互联网 发布:软件下载app 编辑:程序博客网 时间:2024/05/22 17:23

一致性hash(consistent hash)

核心代码:

private Invoker<T> sekectForKey(long hash) {            Invoker<T> invoker;            Long key = hash;            if (!virtualInvokers.containsKey(key)) {                SortedMap<Long, Invoker<T>> tailMap = virtualInvokers.tailMap(key);                if (tailMap.isEmpty()) {                    key = virtualInvokers.firstKey();                } else {                    key = tailMap.firstKey();                }            }            invoker = virtualInvokers.get(key);            return invoker;        }

其中virtualInvokers是一棵红黑树,tailMap方法会返回所有hash值大于key的节点,然后取第一个节点即可。其中key值是根据调用的参数md5后再hash计算得出的:

public Invoker<T> select(Invocation invocation) {            String key = toKey(invocation.getArguments());            byte[] digest = md5(key);            Invoker<T> invoker = sekectForKey(hash(digest, 0));            return invoker;        }
随机:(Random)

 protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {        int length = invokers.size(); // 总个数        int totalWeight = 0; // 总权重        boolean sameWeight = true; // 权重是否都一样        for (int i = 0; i < length; i++) {            int weight = getWeight(invokers.get(i), invocation);            totalWeight += weight; // 累计总权重            if (sameWeight && i > 0                    && weight != getWeight(invokers.get(i - 1), invocation)) {                sameWeight = false; // 计算所有权重是否一样            }        }        if (totalWeight > 0 && ! sameWeight) {            // 如果权重不相同且权重大于0则按总权重数随机            int offset = random.nextInt(totalWeight);            // 并确定随机值落在哪个片断上            for (int i = 0; i < length; i++) {                offset -= getWeight(invokers.get(i), invocation);                if (offset < 0) {                    return invokers.get(i);                }            }        }        // 如果权重相同或权重为0则均等随机        return invokers.get(random.nextInt(length));    }
可以看到是按照权重来路由的,生成一个随机数,看这个随机数落在哪个invoker的权重区间上,那么就会调用哪个invoker。如果权重大,那么执行的机会就会多些。

轮询:(RoundRobin )

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(); // 总个数        int maxWeight = 0; // 最大权重        int minWeight = Integer.MAX_VALUE; // 最小权重        for (int i = 0; i < length; i++) {            int weight = getWeight(invokers.get(i), invocation);            maxWeight = Math.max(maxWeight, weight); // 累计最大权重            minWeight = Math.min(minWeight, weight); // 累计最小权重        }        if (maxWeight > 0 && minWeight < maxWeight) { // 权重不一样            AtomicPositiveInteger weightSequence = weightSequences.get(key);            if (weightSequence == null) {                weightSequences.putIfAbsent(key, new AtomicPositiveInteger());                weightSequence = weightSequences.get(key);            }            List<Invoker<?>> listInvoker = weightInvokers.get(key);            if (listInvoker == null) {            weightInvokers.putIfAbsent(key, new ArrayList<Invoker<?>>());            listInvoker = weightInvokers.get(key);            }            synchronized(listInvoker){            if(listInvoker.isEmpty()){             // 重新构建             int currentWeight = weightSequence.getAndIncrement() % maxWeight;             for (Invoker<T> invoker : invokers) { // 筛选权重值大于等于当前权重基数的Invoker                     if (getWeight(invoker, invocation) >= currentWeight) {                     listInvoker.add(invoker);                     }                 }            }            return invokers.remove(0);            }        }        AtomicPositiveInteger sequence = sequences.get(key);        if (sequence == null) {            sequences.putIfAbsent(key, new AtomicPositiveInteger());            sequence = sequences.get(key);        }        // 取模轮循        return invokers.get(sequence.getAndIncrement() % length);    }
上面是修改后的代码,原来的代码有bug。逻辑很简单:基础权重从0开始逐渐增大到最大的权重,计算所有大于基础权重的invoker,并且依次调用。比如说有两个invoker:I1,I2的权重分别是权重4,7。那么I1的权重大于0,1,2,3基础权重,那么会被调用4次,而I2的权重大于0,1,2,3,4,5,6基础权重,所以会被调用7次,这样I1和I2被调用的次数之比就是4:7。


0 0