前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dubbo 的负载均衡策略:轮询策略

Dubbo 的负载均衡策略:轮询策略

作者头像
LieBrother
发布2019-04-02 10:51:16
2.8K0
发布2019-04-02 10:51:16
举报
文章被收录于专栏:LieBrotherLieBrother

本文简单介绍 Dubbo 负载均衡策略中的轮询策略。

1

轮询负载均衡策略

Dubbo 中实现轮询策略的代码是:RoundRobinLoadBalance。这个策略和随机策略有一个比较大的差异在于,轮询策略需要知道上次是哪个实例被调用了,Dubbo 是记录了每个被调用的方法被调用的次数,因为只需要通过取余计算就可以得到这一次要调用的实例,不用直接记录上一次被调用的实例。

轮询的策略算法也是分为 2 种情况。

  • 被调用的服务的所有实例都没有权重 当所有实例都没有权重的时候,则通过 [调用总次数 + 1] % [实例数],就可以获取到这次要调用的实例
  • 被调用的服务的实例的权重不一 举个例子来说比较形象一点,如下图所示,假设有 A - F 总共 6 个实例,分别是如下权重。最大的权重 maxWeight = 200,通过 [调用总次数 + 1] % [总的权重值] 得到这次要选中的偏移量 mod,实现算法是顺时针遍历实例,如果不是选中所在的实例,则实例的权重 减 1,mod 也减 1,一直循环到 mod 为 0时,所在的实例的权重不为 0 ,则选中实例。也就是说这个圆会一直变小,ABCDEF遍历,如果没选中,这 6 个实例的权重都减 1,这才保证权重大的选中的几率高。不像随机策略,随机策略就是直接定位偏移量 mod 的位置在哪个实例。

2

轮询策略的优缺点

  • 优点:实现简单,易水平扩展,且比较均衡分发到所有实例
  • 缺点:无法知道所有的实例的情况。

3

RoundRobinLoadBalance 源码

代码语言:javascript
复制
public class RoundRobinLoadBalance extends AbstractLoadBalance {

    public static final String NAME = "roundrobin";

    // 记录所有提供服务的数据,<serviceKey+methodName, 调用次数>
    private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();

    @Override
    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) {
            // 将调用次数 % 权重总数,得出偏移量 mod
            int mod = currentSequence % weightSum;
            // 遍历最大的权重值,
            // 为什么会遍历它?
            // 因为每一次循环就遍历所有的实例,一个实例最大的权重为 maxWeight,
            // 最多遍历 maxWeight 次所有实例就可以找到想要的实例
            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) {
                        // mod 为 0 表示选中了,但要满足该实例的权重大于 0
                        return k;
                    }
                    if (v.getValue() > 0) {
                        // 实例没选中,则权重减 1,相当于选中机会少了
                        v.decrement();
                        // 偏移量也减 1
                        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--;
        }
    }

}

做个有梦想的程序猿

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 LieBrother 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档