dubbo源码分析第二十三篇一dubbo负载均衡-LeastActiveLoadBalance与预热机制
  Ojuk44AdL5AF 2023年11月02日 96 0


文章目录

  • ​​LeastActiveLoadBalance​​
  • ​​源码分析​​
  • ​​预热机制​​

LeastActiveLoadBalance

  • 通过ActiveLimitFilter设置每个Invoker方法的活跃数,方法调用前+1,调用后-1
  • 获取活跃数最小的Invoker
  • 存在多个最小活跃数相同Invoker,根据权重配置随机获取
  • 存在多个最小活跃数相同Invoker,权重全部相同,随机获取

源码分析

  • 根据Invoker信息计算最小活跃数Invoker
  • 根据最小活跃数数量,判断直接获取Invoker,加权随机获取Invoker,还是普通随机
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
int length = invokers.size();
所有调用者中最小活跃数
int leastActive = -1;
最小活跃数相同的Invoker数量
int leastCount = 0;
int[] leastIndexes = new int[length];
int[] weights = new int[length];
所有最不活跃的调用者的预热权重的总和
int totalWeight = 0;
第一个最不活跃的调用者的权重
int firstWeight = 0;

boolean sameWeight = true;
根据Invoker的活跃数计算最小活跃数
for (int i = 0; i < length; i++) {
Invoker<T> invoker = invokers.get(i);
获取当前url下的方法对应的活跃数,活跃数通过filter机制设置
int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
默认权重100,当启动时间小于预热时间[启动时间/预热时间]*100
int afterWarmup = getWeight(invoker, invocation);
每个Invoker的权重
weights[i] = afterWarmup;
if (leastActive == -1 || active < leastActive) {
第一个Invoker的最小权重或者出现新的最小权重Invoker
leastActive = active;
// Reset the number of least active invokers
leastCount = 1;
// Put the first least active invoker first in leastIndexes
leastIndexes[0] = i;
// Reset totalWeight
totalWeight = afterWarmup;
// Record the weight the first least active invoker
firstWeight = afterWarmup;

sameWeight = true;

} else if (active == leastActive) {
出现最小活跃数和已经统计的最小活跃数相同
leastIndexes[leastCount++] = i;
累计总权重
totalWeight += afterWarmup;
存在权重不同 则使用step-2 b 加权随机
if (sameWeight && afterWarmup != firstWeight) {
sameWeight = false;
}
}
}

step-2: 获取Invoker
a 最小权重的Invoker数量相同的只有一个
if (leastCount == 1) {
return invokers.get(leastIndexes[0]);
}
b 最小权重的Invoker数量相同有多个 并且权重不相同
if (!sameWeight && totalWeight > 0) {
随机一个值
int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
for (int i = 0; i < leastCount; i++) {
int leastIndex = leastIndexes[i];
判断随机的权重在不在当前加权权重范围
offsetWeight -= weights[leastIndex];
if (offsetWeight < 0) {
return invokers.get(leastIndex);
}
}
}
c 权重全部相同或者总权重为0,直接随机获取
return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);
}
预热机制
  • 默认启动服务的前10分钟称为预热期
  • 这10分钟的权重并非配置的weight值,而是(now-start)/10分钟*weight
  • 目的是为了减小对刚启动的机器的调用
int getWeight(Invoker<?> invoker, Invocation invocation) {
int weight;
URL url = invoker.getUrl();
// Multiple registry scenario, load balance among multiple registries.
if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) {
weight = url.getParameter(REGISTRY_KEY + "." + WEIGHT_KEY, DEFAULT_WEIGHT);
} else {
// 从 url 中获取权重 weight 配置值 默认权重100
weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
if (weight > 0) {
// 获取服务提供者启动时间戳
long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L);
if (timestamp > 0L) {
// 计算服务提供者运行时长
long uptime = System.currentTimeMillis() - timestamp;

if (uptime < 0) {
return 1;
}
// 如果服务运行时间小于预热时间,则重新计算服务权重,即降权
// warmup默认10分钟
int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
if (uptime > 0 && uptime < warmup) {
weight = calculateWarmupWeight((int)uptime, warmup, weight);
}
}
}
}
return Math.max(weight, 0);
}




【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  ehrZuhofWJiC   2024年04月26日   42   0   0 日志Java
Ojuk44AdL5AF