Java实现负载均衡算法--轮询和加权轮询
1.普通轮询算法
轮询(Round Robin,RR)是依次将用户的访问请求,按循环顺序分配到web服务节点上,从1开始到最后一台服务器节点结束,然后再开始新一轮的循环。这种算法简单,但是没有考虑到每台节点服务器的具体性能,请求分发往往不均衡。
代码实现:
/** * 普通轮询算法
*/public class RoundRobin {
private static Integer index = 0;
private static List<String> nodes = new ArrayList<>();
// 准备模拟数据
static {
nodes.add("192.168.1.101");
nodes.add("192.168.1.103");
nodes.add("192.168.1.102");
System.out.println("普通轮询算法的所有节点:"+nodes);//打印所有节点
}
// 关键代码
public String selectNode(){
String ip = null;
synchronized (index){
// 下标复位
if(index>=nodes.size()) index = 0;
ip = nodes.get(index);
index++;
}
return ip;
}
// 并发测试:两个线程循环获取节点
public static void main(String[] args) {
new Thread(() -> {
RoundRobin roundRobin1 = new RoundRobin();
for (int i=1;i<=5;i++){
String serverIp = roundRobin1.selectNode();
System.out.println(Thread.currentThread().getName()+"==第"+i+"次获取节点:"+serverIp);
}
}).start();
RoundRobin roundRobin2 = new RoundRobin();
for (int i=1;i<=nodes.size();i++){
String serverIp = roundRobin2.selectNode();
System.out.println(Thread.currentThread().getName()+"==第"+i+"次获取节点:"+serverIp);
}
}
}
执行结果:不同线程访问,结果依旧是按顺序循环分配节点
普通轮询算法的所有节点:[192.168.1.101, 192.168.1.103, 192.168.1.102]
main==第1次获取节点:192.168.1.101
Thread-0==第1次获取节点:192.168.1.103
Thread-0==第2次获取节点:192.168.1.102
Thread-0==第3次获取节点:192.168.1.101
Thread-0==第4次获取节点:192.168.1.103
Thread-0==第5次获取节点:192.168.1.102
main==第2次获取节点:192.168.1.101
main==第3次获取节点:192.168.1.103
2.加权轮询算法
加权轮询(Weighted Round Robin,WRR)是根据设定的权重值来分配访问请求,权重值越大的,被分到的请求数也就越多。一般根据每台节点服务器的具体性能来分配权重。
2.1.实现方式一
将需要轮询的所有节点按权重数循环生成一个List 集合,然后就跟普通轮询算法一样,来一个、分配一个、进1位。
例如:
所有节点信息:{{“192.168.1.100“,5},{“192.168.1.101“,1},{“192.168.1.102“,3}}
那么生成的List 集合为:
{“192.168.1.100“,
“192.168.1.100“,
“192.168.1.100“,
“192.168.1.100“,
“192.168.1.100“,
“192.168.1.101“,
“192.168.1.102“,
“192.168.1.102“,
“192.168.1.102“}
后面就是普通轮询算法的逻辑
代码实现:
类似于二维数组 降维成 一维数组,然后使用普通轮询
/** * 简单版的加权轮询
*/public class WeightedRoundRobinSimple {
private static Integer index = 0;
private static Map<String,Integer> mapNodes = new HashMap<>();
// 准备模拟数据
static {
mapNodes.put("192.168.1.101",1);
mapNodes.put("192.168.1.102",3);
mapNodes.put("192.168.1.103",2);
/* -- 以下代码只为了方便查看所有节点,删除不影响 -- S */
List<String> nodes = new ArrayList<>();
Iterator<Map.Entry<String, Integer>> iterator = mapNodes.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, Integer> entry = iterator.next();
String key = entry.getKey();
for (int i=0;i<entry.getValue();i++){
nodes.add(key);
}
}
System.out.println("简单版的加权轮询:"+nodes);//打印所有节点
/* -- 以上代码只为了方便查看所有节点,删除不影响-- E */
}
// 关键代码:类似于二维数组 降维成 一维数组,然后使用普通轮询
public String selectNode(){
List<String> nodes = new ArrayList<>();
Iterator<Map.Entry<String, Integer>> iterator = mapNodes.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, Integer> entry = iterator.next();
String key = entry.getKey();
for (int i=0;i<entry.getValue();i++){
nodes.add(key);
}
}
String ip = null;
synchronized (index){
// 下标复位
if(index>=nodes.size()) index = 0;
ip = nodes.get(index);
index++;
}
return ip;
}
// 并发测试:两个线程循环获取节点
public static void main(String[] args) {
new Thread(() -> {
WeightedRoundRobinSimple roundRobin1 = new WeightedRoundRobinSimple();
for (int i=1;i<=6;i++){
String serverIp = roundRobin1.selectNode();
System.out.println(Thread.currentThread().getName()+"==第"+i+"次获取节点:"+serverIp);
}
}).start();
WeightedRoundRobinSimple roundRobin2 = new WeightedRoundRobinSimple();
for (int i=1;i<=6;i++){
String serverIp = roundRobin2.selectNode();
System.out.println(Thread.currentThread().getName()+"==第"+i+"次获取节点:"+serverIp);
}
}
}
执行结果:两个线程循环测试,输出结果会出现交替分配到不同的IP,但最终的效果都是一个个按顺序分配,类似于普通轮询算法。
简单版的加权轮询:[192.168.1.103, 192.168.1.103, 192.168.1.101, 192.168.1.102, 192.168.1.102, 192.168.1.102]
main==第1次获取节点:192.168.1.103
main==第2次获取节点:192.168.1.103
main==第3次获取节点:192.168.1.101
main==第4次获取节点:192.168.1.102
main==第5次获取节点:192.168.1.102
Thread-0==第1次获取节点:192.168.1.102
Thread-0==第2次获取节点:192.168.1.103
main==第6次获取节点:192.168.1.103
Thread-0==第3次获取节点:192.168.1.101
Thread-0==第4次获取节点:192.168.1.102
Thread-0==第5次获取节点:192.168.1.102
Thread-0==第6次获取节点:192.168.1.102
2.2.实现方式二(重点难点)
本文的重点难点。
在实现方式一的算法中可以很明显的看到,同权重的IP会被连续分配,也就是说同一个IP在短时间内收到不同的请求,过了这个连续点,就要等到下一轮才会被分配到,并没有做到均匀分配节点。
实现方式二将尽可能地均匀分配每个节点,节点分配不再是连续的,但最终的权重比和上一个方式一样,这种加权轮询又被称为平滑加权轮询。
理解关键的几个参数和算法逻辑,方便理解代码的实现。
2.2.1.概述
关键参数
ip:负载IP 以上是 Java实现负载均衡算法--轮询和加权轮询 的全部内容, 来源链接: utcz.com/z/395085.html