目录
1.LoadBalance
默认实现是RandomLoadBalance,对RegistryDirectory#list()出来的Invokers进行选择,然后发起访问
@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {
@Adaptive("loadbalance")
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}
2.AbstractLoadBalance
1.select()
public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {
if (CollectionUtils.isEmpty(invokers)) {
return null;
}
// 如果只有一个 那不需要负载算法选择
if (invokers.size() == 1) {
return invokers.get(0);
}
// 模板方法 由子类实现
return doSelect(invokers, url, invocation);
}
2.getWeight()
protected int getWeight(Invoker<?> invoker, Invocation invocation) {
// 获取 sayHello.weight 或者 weight,默认权重都是100
int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
// 如果设置了服务热身时间 且当前的服务上线时间还没到热身时间 会综合热身时间计算权重
if (weight > 0) {
long timestamp = invoker.getUrl().getParameter(REMOTE_TIMESTAMP_KEY, 0L);
if (timestamp > 0L) {
int uptime = (int) (System.currentTimeMillis() - timestamp);
int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
if (uptime > 0 && uptime < warmup) {
weight = calculateWarmupWeight(uptime, warmup, weight);
}
}
}
return weight >= 0 ? weight : 0;
}
3.RandomLoadBalance
随机加权负载算法:假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上。比如数字3会落到服务器 A 对应的区间上,此时返回服务器 A 即可。
权重越大的机器,在坐标轴上对应的区间范围就越大,因此随机数生成器生成的数字就会有更大的概率落到此区间内。只要随机数生成器产生的随机数分布性很好,在经过多次选择后,每个服务器被选中的次数比例接近其权重比例。
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
int length = invokers.size();
boolean sameWeight = true; // 是否权重相同
int[] weights = new int[length]; // 权重数组 记录每个Invoker的权重
// 拿到Invokers列表中第一个Invoker的权重
int firstWeight = getWeight(invokers.get(0), invocation);
weights[0] = firstWeight;
// 统计所有Invoker的权重之和
int totalWeight = firstWeight;
// 遍历Invoker列表 将每个Invoker对应的权重保存进数组
// 然后累加权重之和 判断每个Invoker权重是否相同
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;
}
}
// 权重不相同的处理
// 1.首先计算一个大于等于0、小于总权重的随机数,作为offset
// 2.遍历权重数组,让每一个Invoker对应的权重去减offset,并更新offset值
// 3.啥时候把这个offset减为小于等于0了,就说明当前权重对应的Invoker就是要选择的
if (totalWeight > 0 && !sameWeight) {
int offset