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均衡算法)

最少活跃数

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏King_3的技术专栏

leetcode-461-Hamming Distance

1334
来自专栏nummy

pandas将含有多值的内容分拆成多行

在同一列中,本该分别填入多行中的数据,被填在一行里了,然而在分析的时候,需要拆分成为多行。

762
来自专栏ACM小冰成长之路

51Nod-1203-JZPLCM

ACM模版 描述 ? 题解 这个题的解法好像好多好多,可以线段树解,自然也可以用树状数组解,还有大佬直接莫队推过,我这里用的树状数组搞得。 首先将数进行拆解,拆...

17010
来自专栏python3

python3--尝试写一个三级菜单

632
来自专栏码农阿宇

JustMock .NET单元测试利器(三)用JustMock测试你的应用程序

用JustMock测试你的应用程序 本主题将指导您通过几个简单的步骤来使用Telerik®JustMock轻松测试您的应用程序。您将理解一个简单的原理,称为Ar...

3597
来自专栏刘望舒

LeakCanary看这一篇文章就够了

LeakCanary是Square公司基于MAT开源的一个内存泄漏检测工具,在发生内存泄漏的时候LeakCanary会自动显示泄漏信息。

1825
来自专栏跟着阿笨一起玩NET

linq to sql 扩展方法

440
来自专栏跟着阿笨一起玩NET

UML图示与代码对照

本文转载:http://www.cnblogs.com/iamlilinfeng/archive/2012/08/29/2662740.html

380
来自专栏何俊林

LeakCanary的原理,你知道么?

1272
来自专栏代码拾遗

Java8 Date Time API

Java8 带来了全新的处理日期和时间的方式。几乎所有人都有使用Java Date API痛苦的经历。因此有很多人切换到了Joda Time,但是Java8现在...

542

扫码关注云+社区