有三个处理服务器A,B,C,权重比为2:3:5,要求根据权重比进行分配任务
方案: 1、随机权重分配根据权重比列,随机生成区间数量来分配,这种有概率,分配量不是百分百按权重来
实现方式:
通过权重生成大小为权重和的数组,比如三台处理机器A,B,C权重比为 2 : 3 :5,由在10内随机生成数来决定取列表那个位置。
因为数组内的每个服务器数量是按照权重来的,所以只要数量足够大,取得的服务器概率理论上是无限接近于权重比的
加权轮询,分为两种。
(1)一种是普通的
保证任务总数内的任务是按权重比进行分配的,但是可能会导致大量的任务在短时间内分配给一台。比如10个任务,A分配2个,B分配3个,C分配5个,但是在顺序上可能C的5个在一起,然后前面5个任务全部给了C,A和B一个都没,只有当任务第六个的时候才会分配给A或B
实现方式:
就是生成一个大小为权重总和的服务器List,里面每个服务器的元素数量由权重值决定,每次获取索引都加一,如果满了就重置从0开始
(2)一种是平滑加权轮询
保证任务总数内的任务是按权重比进行分配的,且顺序上比较均衡,比如10个任务,A分配2个,B分配3个,C分配5个,第一个是C,第二个是B,第三个是A,再一直往下。
实现方式:
所谓权重,可以理解为能力大小不均衡,从数字角度来看,就是每次递增的大小不一,递减大小一样,那次操作每个服务器的【当前权重】都自增【权重值】(初始固定值),取当前权重最大的一个,被选中则当前权重要减去【权重总和】(初始固定值)。
import com.nw.test.pojo.ServerNode;
import java.util.*;
public class WeightedRobinServiceImpl {
private final List serverNodeList;
private int index;
private final int weightTotal;
public WeightedRobinServiceImpl(List list) {
this.index = 0;
this.serverNodeList = list;
this.weightTotal = list.stream().mapToInt(ServerNode::getWeight).sum();
}
public synchronized String smoothSelectServer() {
if (serverNodeList.isEmpty()) {
return null;
}
ServerNode maxServerNode = serverNodeList.stream().max(Comparator.comparingInt(ServerNode::getCurrentWeight)).get();
serverNodeList.forEach(serverNode -> {
/ * 参考其它文章的话,节点还有一个偏移权重属性,初始值为权重值,这个偏移权重是用来实时调整服务器能力的,
* 每次选举的时候,当前权重就要加上偏移权重,每次选择了这个服务器,但是这个服务器响应失败(比如请求堵塞、网络波动),那么就把他的偏移值减一
* 相反,选择这个服务器响应成功(说明服务器响应能力变好或至少没变差),那么他的偏移值就加1,但是不能超过权重值
* 我们这里测试模拟的肯定没有响应失败的情况,所以不要偏移权重字段,直接也是加的权重值(固定,标识响应能力一直不变)
* /
serverNode.setCurrentWeight(serverNode.getCurrentWeight() + serverNode.getWeight());
if (serverNode.equals(maxServerNode)) {
serverNode.setCurrentWeight(serverNode.getCurrentWeight() - weightTotal);
}
});
return maxServerNode.getIp();
}
public synchronized String selectServer() {
if (serverNodeList.isEmpty()) {
return null;
}
List nodeList = new ArrayList<>();
serverNodeList.forEach(serverNode -> {
Integer weight = serverNode.getWeight();
for (int i = 0; i < weight; i++) {
nodeList.add(serverNode.getIp());
}
});
if (index >= nodeList.size()) {
index = 0;
}
String s = nodeList.get(index);
index++;
return s;
}
public synchronized String randomSelectServer() {
if (serverNodeList.isEmpty()) {
return null;
}
List nodeList = new ArrayList<>();
serverNodeList.forEach(serverNode -> {
Integer weight = serverNode.getWeight();
for (int i = 0; i < weight; i++) {
nodeList.add(serverNode.getIp());
}
});
Random random = new Random();
// 在权重范围内随机
int n = random.nextInt(weightTotal);
return nodeList.get(n);
}
}
节点类
public class ServerNode {
private String ip;
private Integer weight;
private Integer currentWeight;
public ServerNode(String ip, Integer weight) {
this.ip = ip;
this.weight = weight;
this.currentWeight = weight;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public Integer getCurrentWeight() {
return currentWeight;
}
public void setCurrentWeight(Integer currentWeight) {
this.currentWeight = currentWeight;
}
@Override
public String toString() {
return "ServerNode{" +
"ip='" + ip + ''' +
", weight=" + weight +
", currentWeight=" + currentWeight +
'}';
}
}
测试:
@Test
void weightedRobinServiceTest() {
List list = new ArrayList<>();
list.add(new ServerNode("192.168.0.1", 2));
list.add(new ServerNode("192.168.0.2", 3));
list.add(new ServerNode("192.168.0.3", 5));
WeightedRobinServiceImpl weightedRobinService = new WeightedRobinServiceImpl(list);
Scanner scanner = new Scanner(System.in);
while (true){
System.out.println("请输入需要处理的数量: ");
if (scanner.hasNext()) {
List arr = new ArrayList<>();
int amount = scanner.nextInt();
if (amount == 9999) {
weightedRobinService.unload();
break;
}
for (int i = 0; i < amount; i++) {
// String s = weightedRobinService.smoothSelectServer();
// String s = weightedRobinService.selectServer();
String s = weightedRobinService.randomSelectServer();
System.out.println(s);
arr.add(s);
}
Map collect = arr.stream().collect(Collectors.groupingBy(s -> s, Collectors.counting()));
collect.forEach((key, value)->{
System.out.println("处理服务器ip: "+key+", 次数为:"+value);
});
System.out.println("---------------------------------------------");
}
}
}
------------------平滑加权轮询--------------------------
结果是相对分散的
------------------普通加权--------------------------
他的结果是集中的
------------------随机加权--------------------------
参考:
https://blog.csdn.net/loveyour_1314/article/details/121781952
https://my.oschina.net/u/4047016/blog/4420117



