RandomLoadBalance加权随机RoundRobinLoadBalance加权轮询
源码分析
RandomLoadBalance加权随机权重不同则加权随机权重相同则直接随机权重同最小活跃数一样,前10分钟预热阶段,权重从0到配置的weight随时间平滑增长
protectedRoundRobinLoadBalance加权轮询Invoker doSelect(List > invokers, URL url, Invocation invocation) { int length = invokers.size(); boolean sameWeight = true; int[] weights = new int[length]; int firstWeight = getWeight(invokers.get(0), invocation); weights[0] = firstWeight; int totalWeight = firstWeight; for (int i = 1; i < length; i++) { 获取权重 int weight = getWeight(invokers.get(i), invocation); weights[i] = weight; 获取总权重 totalWeight += weight; 判断是否存在权重不同 if (sameWeight && weight != firstWeight) { sameWeight = false; } } 存在加权不同 if (totalWeight > 0 && !sameWeight) { int offset = ThreadLocalRandom.current().nextInt(totalWeight); // 循环让 offset 数减去服务提供者权重值,当 offset 小于0时,返回相应的 Invoker。 // 举例说明一下,我们有 servers = [A, B, C],weights = [5, 3, 2],offset = 7。 // 第一次循环,offset - 5 = 2 > 0,即 offset > 5, // 表明其不会落在服务器 A 对应的区间上。 // 第二次循环,offset - 3 = -1 < 0,即 5 < offset < 8, // 表明其会落在服务器 B 对应的区间上 for (int i = 0; i < length; i++) { offset -= weights[i]; if (offset < 0) { return invokers.get(i); } } } 加权全部相同 return invokers.get(ThreadLocalRandom.current().nextInt(length)); }
轮询逻辑: 根据[权重]增加所有Invoker的[轮询值] ([轮询值] += [权重]) [轮询值]大于当前最大值,作为本次被选中Invoker [轮询值] 减少所有Invoker[权重] ([轮询值] -= total[权重]) 权重: weight 轮询值: current
一个周期后,所有的Invoker的current[轮询值]基本回归,如果权重相同,回归至0
源码分析protectedInvoker doSelect(List > invokers, URL url, Invocation invocation) { 获取当前调用方法的 加权轮询元信息(WeightedRoundRobin) String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName(); {methodWeightMap: key->当前方法,val-> 所有Invoker对应的轮询信息} {map,当前所有的invoker key -> 当前Invoker的唯一id ,val -> 当前的轮询信息 } ConcurrentMap map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>()); int totalWeight = 0; long maxCurrent = Long.MIN_VALUE; long now = System.currentTimeMillis(); Invoker selectedInvoker = null; WeightedRoundRobin selectedWRR = null; 所有的Invoker遍历处理 for (Invoker invoker : invokers) { 获取当前invoker的唯一标识 String identifyString = invoker.getUrl().toIdentityString(); 获取每一个Invoker的权重 int weight = getWeight(invoker, invocation); 给每一个轮询信息设置权重 WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> { WeightedRoundRobin wrr = new WeightedRoundRobin(); wrr.setWeight(weight); return wrr; }); if (weight != weightedRoundRobin.getWeight()) { weightedRoundRobin.setWeight(weight); } 每次增加自己的当前轮询值为权重weight long cur = weightedRoundRobin.increaseCurrent(); weightedRoundRobin.setLastUpdate(now); 找出当前轮询值最小的Invoker if (cur > maxCurrent) { maxCurrent = cur; selectedInvoker = invoker; selectedWRR = weightedRoundRobin; } totalWeight += weight; } if (invokers.size() != map.size()) { 如果一个WeightedRoundRobin 60秒都没有参与过for循环里的轮询处理,则移除该Invoker 就要借助methodWeightMap记忆轮询的信息,又清除了Invoker变动残存的轮询信息 map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD); } if (selectedInvoker != null) { 每次被选中后,当前的轮询值减去所有Invoker的轮询值 从而达到轮询效果 selectedWRR.sel(totalWeight); return selectedInvoker; } 永远不会走到,兜底逻辑 return invokers.get(0); }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)