写在前面
通过客户端实现负载均衡算法(包括随机,轮询,一致性哈希),要求在客户端使用参数指定负载均衡策略和调用次数,调用不同的服务端。
- 三台服务器,一台客户端
- 由于只在一台机器上进行实现,三台服务器的不同由端口号来区分
- 客户端,服务端均采用spring-boot暴露Restful接口
三种负载均衡策略
服务器列表
import java.util.*;
public class ServerPath {
//不带权重的服务路径列表
public static final List<String> LIST = Arrays.asList(
"8081",
"8082",
"8083"
);
//带有权重的 服务路径 列表
public static final Map<String,Integer> WEIGHT_LIST = new LinkedHashMap<>();
static {
WEIGHT_LIST.put("8081",20);
WEIGHT_LIST.put("8082",30);
WEIGHT_LIST.put("8083",50);
}
}
随机算法
随机算法顾名思义,从一些服务器列表中随机挑选出一个服务器来进行负载操作,强调随机性。
但只是简单随机会有一些问题,如果我们有3台服务器,运算效率差距很大,第一台运算效率100分,第二台50分,第三台1分,那么我们简单随机的话,显然无法发挥第一台高性能服务器的优势,所以带权重的随机算法更加优秀。
-
8081端口,权重20
-
8082端口,权重30
-
8083端口,权重50
-
按权重构造一个长度为20+30+50的一维坐标轴,总和为100,则在0~100之间取一个随机数,根据随机数所在的区间来选择具体的服务器。
-
|0——8081——20|21———8082———50|51—————8083—————100|
-
若随机数为 35, 则 20<35<50,选择8082端口服务器。
代码实现
import com.balanceLoad.client.ServerPath;
import java.util.Random;
public class RandomBalance {
public static String getServerPath(){
Random random = new Random();
int total = 0;
//从服务器端口列表中取权重累加到total
for(Integer weight : ServerPath.WEIGHT_LIST.values()){
total +=weight;
}
int x = random.nextInt(total);
return GetPath.getPath(x);
}
public static void main(String[] args) {
for(int i =0;i<10;i++){
System.out.println(getServerPath());
}
}
}
GetPath类
public class GetPath {
public static String getPath(int pos){
for(String port : ServerPath.WEIGHT_LIST.keySet()){
int weight = ServerPath.WEIGHT_LIST.get(port);
if(pos<weight){
return port;
}
pos -= weight;
}
return "";
}
}
轮询算法(平滑加权轮询)
朴素的轮询方法,如果大权重的服务器排在前面,会造成对某台机器请求过多,而排在后面的服务器在请求数较少的时候,可能都没有机会参与负载。
例如权重100的服务器A排在首位,后面跟着权重20的服务B和权重5的服务器C,如果每次服务器集群运行期间请求数都小于100,那么BC服务器基本上都没法参与负载。
例如
- 8081端口,权重20
- 8082端口,权重30
- 8083端口,权重50
- 调用10次服务,朴素的轮询调用序列为:
8081
8081
8082
8082
8082
8083
8083
8083
8083
8083
使用平滑轮询,可以优化为如下序列:
8083
8082
8081
8083
8082
8083
8083
8081
8082
8083