当前位置:   article > 正文

dubbo学习三-负载均衡策略_loadbalance dubboreference

loadbalance dubboreference

1 负载均衡策略介绍

dubbo负载均衡包括4种,随机、轮询、最小活跃调用数、IP哈希
Dubbo负载均衡类图如下

Dubbo使用负载均衡方式很简单,只需要在服务调用者标签上配置loadbalance属性就行

1.1 随机(默认)

@Reference(loadbalance = "random")

如果配置了权重,则invoker权重越大,执行的概率越大;如果没有配置权重,则随机选择invoker执行

1.2 轮询

@Reference(loadbalance = "roundrobin")

如果配置了权重,则根据权重轮询;否则直接通过方法调用次数取模

1.3 最小活跃数

@Reference(loadbalance = "leastactive")

指的是当请求调用来临,有多个实例提供服务的时候,选择其中被调用活跃次数最少的实例来提供服务。通俗一点讲就是,当前有 3 个实例在提供服务,A 当前被 2 个服务调用,B 当前被 3 个服务调用,C 当前被 1 个服务调用,一个新的调用请求过来,会选择调用到 C 实例。
能动态的根据当前服务的调用情况,选择最小被调用的实例,调用越慢的机器,会接收到更少的请求。因为调用越慢的机器调用间隔越大,累积的请求越多

1.4 一致性哈希

@Reference(loadbalance = "consistenthash")

相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。

2 实现原理

2.1 随机算法RandomLoadBalance

  1. protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
  2.     // 获取所有的服务提供者invoker数量
  3.     int length = invokers.size();
  4.     // 初始化总权重为0
  5.     int totalWeight = 0;
  6.     // 默认权重都相等
  7.     boolean sameWeight = true;
  8.     int offset;
  9.     int i;
  10.     for(offset = 0; offset < length; ++offset) {
  11.         // 获取某个invoker的权重(可以在@Server注解上配置)
  12.         i = this.getWeight((Invoker)invokers.get(offset), invocation);
  13.         totalWeight += i;
  14.         if (sameWeight && offset > 0 && i != this.getWeight((Invoker)invokers.get(offset - 1), invocation)) {
  15.             // 如果任意相邻两个invoker权重不相等则把sameWeight设置为false
  16.             sameWeight = false;
  17.         }
  18.     }
  19.     // 下面是轮询权重算法
  20.     if (totalWeight > 0 && !sameWeight) {
  21.         // 从0-totalWeight中随机选取一个数
  22.         offset = this.random.nextInt(totalWeight);
  23.         for(i = 0; i < length; ++i) {
  24.             // 这个数减去该invoker的offset
  25.             offset -= this.getWeight((Invoker)invokers.get(i), invocation);
  26.             if (offset < 0) {
  27.                 // 如果相减后的值<0则用该invoker,权重越大,相减后<0的概率越大
  28.                 return (Invoker)invokers.get(i);
  29.             }
  30.         }
  31.     }
  32.     // 如果权重都相同或者权重算法相减后都>0则随机选一个
  33.     return (Invoker)invokers.get(this.random.nextInt(length));
  34. }

2.2 轮询RoundRobinLoadBalance

  1. protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
  2.     // 用全类名和方法名做key
  3.     String key = ((Invoker)invokers.get(0)).getUrl().getServiceKey() + "." + invocation.getMethodName();
  4.     // 获取invoker的数量
  5.     int length = invokers.size();
  6.     int maxWeight = 0;
  7.     int minWeight = 2147483647;
  8.     // 做一个invoker-weight map
  9.     LinkedHashMap<Invoker<T>, RoundRobinLoadBalance.IntegerWrapper> invokerToWeightMap = new LinkedHashMap();
  10.     int weightSum = 0;
  11.     int currentSequence;
  12.     for(int i = 0; i < length; ++i) {
  13.         // 当前invoker权重
  14.         currentSequence = this.getWeight((Invoker)invokers.get(i), invocation);
  15.         // 设置最大权重和最小权重
  16.         maxWeight = Math.max(maxWeight, currentSequence);
  17.         minWeight = Math.min(minWeight, currentSequence);
  18.         if (currentSequence > 0) {
  19.             // 如果权重>0则把invoker-weight放到map中
  20.             invokerToWeightMap.put(invokers.get(i), new RoundRobinLoadBalance.IntegerWrapper(currentSequence));
  21.             weightSum += currentSequence;
  22.         }
  23.     }
  24.     // 获取这个方法的执行次数,如果为空则初始化
  25.     AtomicPositiveInteger sequence = (AtomicPositiveInteger)this.sequences.get(key);
  26.     if (sequence == null) {
  27.         this.sequences.putIfAbsent(key, new AtomicPositiveInteger());
  28.         sequence = (AtomicPositiveInteger)this.sequences.get(key);
  29.     }
  30.     // 调用次数自增1
  31.     currentSequence = sequence.getAndIncrement();
  32.     // 如果有权重,则考虑权重因素进行选取
  33.     if (maxWeight > 0 && minWeight < maxWeight) {
  34.         int mod = currentSequence % weightSum;
  35.         for(int i = 0; i < maxWeight; ++i) {
  36.             Iterator i$ = invokerToWeightMap.entrySet().iterator();
  37.             while(i$.hasNext()) {
  38.                 Entry<Invoker<T>, RoundRobinLoadBalance.IntegerWrapper> each = (Entry)i$.next();
  39.                 Invoker<T> k = (Invoker)each.getKey();
  40.                 RoundRobinLoadBalance.IntegerWrapper v = (RoundRobinLoadBalance.IntegerWrapper)each.getValue();
  41.                 if (mod == 0 && v.getValue() > 0) {
  42.                     return k;
  43.                 }
  44.                 if (v.getValue() > 0) {
  45.                     v.decrement();
  46.                     --mod;
  47.                 }
  48.             }
  49.         }
  50.     }
  51.     // 根据方法调用次数取模,一次次来
  52.     return (Invoker)invokers.get(currentSequence % length);
  53. }

2.3 最小活跃数LeastActiveLoadBalance

  1. protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
  2.     // 获取invoker个数
  3.     int length = invokers.size();
  4.     // 最小活跃值
  5.     int leastActive = -1;
  6.     // 最小活跃数量
  7.     int leastCount = 0;
  8.     // 做一个数组,记录最小活跃invoker的下标
  9.     int[] leastIndexs = new int[length];
  10.     int totalWeight = 0;
  11.     int firstWeight = 0;
  12.     boolean sameWeight = true;
  13.     int offsetWeight;
  14.     int leastIndex;
  15.     for(offsetWeight = 0; offsetWeight < length; ++offsetWeight) {
  16.         Invoker<T> invoker = (Invoker)invokers.get(offsetWeight);
  17.         // 获取该实例的活跃值
  18.         leastIndex = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
  19.         int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "weight", 100);
  20.         if (leastActive != -1 && leastIndex >= leastActive) {
  21.             if (leastIndex == leastActive) {
  22.                 // 如果该invoker == 最小活跃度则把该invoker下标记录到leastIndexs中
  23.                 leastIndexs[leastCount++] = offsetWeight;
  24.                 totalWeight += weight;
  25.                 if (sameWeight && offsetWeight > 0 && weight != firstWeight) {
  26.                     sameWeight = false;
  27.                 }
  28.             }
  29.         } else {
  30.             // 如果出现更小活跃度的invoker则重新设置最小活跃度的值
  31.             leastActive = leastIndex;
  32.             // 更新最小活跃度个数为1
  33.             leastCount = 1;
  34.             // 把该invoker下标记录到leastIndexs中
  35.             leastIndexs[0] = offsetWeight;
  36.             totalWeight = weight;
  37.             firstWeight = weight;
  38.             sameWeight = true;
  39.         }
  40.     }
  41.     if (leastCount == 1) {
  42.         // 如果最小活跃数量invoker个数为1则直接返回
  43.         return (Invoker)invokers.get(leastIndexs[0]);
  44.     } else {
  45.         // 如果有多个最小活跃数量的invoker
  46.         if (!sameWeight && totalWeight > 0) {
  47.             // 如果考虑权重则根据权重做随机
  48.             offsetWeight = this.random.nextInt(totalWeight);
  49.             for(int i = 0; i < leastCount; ++i) {
  50.                 leastIndex = leastIndexs[i];
  51.                 offsetWeight -= this.getWeight((Invoker)invokers.get(leastIndex), invocation);
  52.                 if (offsetWeight <= 0) {
  53.                     return (Invoker)invokers.get(leastIndex);
  54.                 }
  55.             }
  56.         }
  57.         // 如果没有权重则从最小活跃度invoker中随机选择一个
  58.         return (Invoker)invokers.get(leastIndexs[this.random.nextInt(leastCount)]);
  59.     }
  60. }

2.4 一致性哈希ConsistentHashLoadBalance

  1. protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
  2.     // 用全类名和方法名做key
  3.     String key = ((Invoker)invokers.get(0)).getUrl().getServiceKey() + "." + invocation.getMethodName();
  4.     // 基于 invokers 集合,根据对象内存地址来计算定义哈希值
  5.     int identityHashCode = System.identityHashCode(invokers);
  6.     // 获取根据key获取本次执行的选择器
  7.     ConsistentHashLoadBalance.ConsistentHashSelector<T> selector = (ConsistentHashLoadBalance.ConsistentHashSelector)this.selectors.get(key);
  8.     if (selector == null || selector.identityHashCode != identityHashCode) {
  9.         this.selectors.put(key, new ConsistentHashLoadBalance.ConsistentHashSelector(invokers, invocation.getMethodName(), identityHashCode));
  10.         selector = (ConsistentHashLoadBalance.ConsistentHashSelector)this.selectors.get(key);
  11.     }
  12.     return selector.select(invocation);
  13. }
  14. public Invoker<T> select(Invocation invocation) {
  15.     // 根据方法参数做key
  16.     String key = this.toKey(invocation.getArguments());
  17.     // 加密
  18.     byte[] digest = this.md5(key);
  19.     // 选取执行的invoker
  20.     return this.selectForKey(this.hash(digest, 0));
  21. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/41325
推荐阅读
相关标签
  

闽ICP备14008679号