负载均衡
类结构
- 我们定义了一个LoadBalance接口,接口里面定义了一个select方法,用来选择网关要将请求转发到哪个服务器;
- 我们定义了一个AbstractLoadBalance抽象类,抽象类主要实现了select方法,以及定义了一个doSelect方法(实现类通过重写doSelect完成各种负载均衡策略);
- 定义了三个不同策略的负载均衡策略来实现AbstractLoadBalance抽象类的doSelect方法,从而实现负载均衡的处理;
Soul源码的负载均衡算法的目录位置如图所示,进入工程的下面目录即可找到Soul的负载均衡源码;
Soul网关支持的负载均衡策略
- Hash算法
- 随机 & 加权随机
- 轮询
下面我们一起看下随机&加权随机负载均衡的实现过程:
随机&加权随机
随机
我们可以看到,在实现类里面的random里面使用RANDOM.nextInt(upstreamList.size())来挑选一个服务器地址进行转发;
加权随机
在使用加权随机负载均衡时,我们会在Soul 的Admin控制台配置各个服务器的权重;
处理过程:
- 计算所有服务器的总权重;
- 判断所有服务器的请求是否一致,如果都一致,直接采用随机策略;
- 我们通过随机函数(RANDOM.nextInt(totalWeight))生成随机偏移量,参数为总的权重值;然后我们通过判断偏移量offset落在哪一个服务器权重区间来判断选择哪一个服务器进行请求转发;
package org.dromara.soul.plugin.divide.balance.spi;
import org.dromara.soul.common.dto.convert.DivideUpstream;
import org.dromara.soul.spi.Join;
import java.util.List;
import java.util.Random;
/**
* random algorithm impl.
*
* @author xiaoyu(Myth)
*/
@Join
public class RandomLoadBalance extends AbstractLoadBalance {
private static final Random RANDOM = new Random();
@Override
public DivideUpstream doSelect(final List<DivideUpstream> upstreamList, final String ip) {
int totalWeight = calculateTotalWeight(upstreamList);
boolean sameWeight = isAllUpStreamSameWeight(upstreamList);
if (totalWeight > 0 && !sameWeight) {
return random(totalWeight, upstreamList);
}
// If the weights are the same or the weights are 0 then random
return random(upstreamList);
}
private boolean isAllUpStreamSameWeight(final List<DivideUpstream> upstreamList) {
boolean sameWeight = true;
int length = upstreamList.size();
for (int i = 0; i < length; i++) {
int weight = getWeight(upstreamList.get(i));
if (i > 0 && weight != getWeight(upstreamList.get(i - 1))) {
// Calculate whether the weight of ownership is the same
sameWeight = false;
break;
}
}
return sameWeight;
}
private int calculateTotalWeight(final List<DivideUpstream> upstreamList) {
// total weight
int totalWeight = 0;
for (DivideUpstream divideUpstream : upstreamList) {
int weight = getWeight(divideUpstream);
// Cumulative total weight
totalWeight += weight;
}
return totalWeight;
}
private DivideUpstream random(final int totalWeight, final List<DivideUpstream> upstreamList) {
// If the weights are not the same and the weights are greater than 0, then random by the total number of weights
int offset = RANDOM.nextInt(totalWeight);
// Determine which segment the random value falls on
for (DivideUpstream divideUpstream : upstreamList) {
offset -= getWeight(divideUpstream);
if (offset < 0) {
return divideUpstream;
}
}
return upstreamList.get(0);
}
private DivideUpstream random(final List<DivideUpstream> upstreamList) {
return upstreamList.get(RANDOM.nextInt(upstreamList.size()));
}
}