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

本文简单介绍 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 源码

public classRoundRobinLoadBalanceextendsAbstractLoadBalance {

public static finalStringNAME="roundrobin";

// 记录所有提供服务的数据,

private finalConcurrentMapsequences=newConcurrentHashMap();

@Override

protected InvokerdoSelect(List> invokers,URL url,Invocation invocation) {

String key = invokers.get().getUrl().getServiceKey() +"."+ invocation.getMethodName();

// 被调用实例数

intlength = invokers.size();// Number of invokers

// 最大权重值

intmaxWeight =;// The maximum weight

// 最小权重值

intminWeight = Integer.MAX_VALUE;// The minimum weight

// 记录每个实例以及对应的权重

finalLinkedHashMap,IntegerWrapper> invokerToWeightMap =newLinkedHashMap,IntegerWrapper>();

// 权重之和

intweightSum =;

// 遍历所有被调用实例

for(inti =;i

// 获取对应实例的权重值

intweight = 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 >) {

// 只添加有权重的实例

invokerToWeightMap.put(invokers.get(i), newIntegerWrapper(weight));

weightSum += weight;

}

}

// 获取该服务的调用次数

AtomicPositiveInteger sequence =sequences.get(key);

if(sequence ==null) {

// 没有调用记录则添加数据

sequences.putIfAbsent(key, newAtomicPositiveInteger());

sequence =sequences.get(key);

}

// 调用次数加一

intcurrentSequence = sequence.getAndIncrement();

// 实例有权重,则根据权重大小分配

if(maxWeight >&& minWeight

// 将调用次数 % 权重总数,得出偏移量 mod

intmod = currentSequence % weightSum;

// 遍历最大的权重值,

// 为什么会遍历它?

// 因为每一次循环就遍历所有的实例,一个实例最大的权重为 maxWeight,

// 最多遍历 maxWeight 次所有实例就可以找到想要的实例

for(inti =;i

// 遍历所有的实例

for(Map.Entry,IntegerWrapper> each : invokerToWeightMap.entrySet()) {

finalInvoker k = each.getKey();

finalIntegerWrapper v = each.getValue();

if(mod ==&& v.getValue() >) {

// mod 为 0 表示选中了,但要满足该实例的权重大于 0

returnk;

}

if(v.getValue() >) {

// 实例没选中,则权重减 1,相当于选中机会少了

v.decrement();

// 偏移量也减 1

mod--;

}

}

}

}

// 没有权重则 调用次数 % 实例数量 对应下标的实例返回

// Round robin

returninvokers.get(currentSequence % length);

}

private static final classIntegerWrapper {

private intvalue;

publicIntegerWrapper(intvalue) {

this.value= value;

}

public intgetValue() {

returnvalue;

}

public voidsetValue(intvalue) {

this.value= value;

}

public voiddecrement() {

this.value--;

}

}

}

做个有梦想的程序猿

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180813G1TRPU00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券