首先我们来看一下什么是负载均衡?
随着业务的发展,单台web服务器已经承载不了系统现在流量的时候,我们就需要部署多台服务器,将流量分散在不同的服务器上,这样可以提高系统的可用性。
我们可以对web请求进行负载均衡,很大的一部分原因是由于HTTP协议的无状态性,同样的请求响应是一样的,所以哪个服务器处理都可以(先不考虑session,考虑session的情况,参见我的另一篇博客)
好了,废话不多说,我们来看一下有哪些负载均衡算法:
1.简单轮询
顾名思义,这个方法是对后端web服务器进行简单的轮询,将请求按顺序发给后端服务器。
但是我们知道,服务器的性能可能是不一样的,每个服务器此刻处理的请求数量也是不一样的,这样简单地轮询,可能满足不了我们系统的要求。因此这个算法一般作为学习使用。
public class RoundRobin {
private static Map<String, Integer> serviceWeightMap = new ConcurrentHashMap<>();
static {
serviceWeightMap.put("192.168.1.100", 1);
serviceWeightMap.put("192.168.1.101", 1);
serviceWeightMap.put("192.168.1.102", 4);
serviceWeightMap.put("192.168.1.103", 1);
serviceWeightMap.put("192.168.1.104", 1);
serviceWeightMap.put("192.168.1.105", 3);
serviceWeightMap.put("192.168.1.106", 1);
serviceWeightMap.put("192.168.1.107", 2);
serviceWeightMap.put("192.168.1.108", 1);
serviceWeightMap.put("192.168.1.109", 1);
serviceWeightMap.put("192.168.1.110", 1);
}
private static Integer pos = 0;
public static String testRoundRobin() {
Set<String> keySet = serviceWeightMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();//为了保证线程安全,做一个类似快照的东西
keyList.addAll(keySet);
String server = null;
synchronized (pos) {
if (pos > keySet.size()) {
pos = 0;
}
server = keyList.get(pos);
pos++;
}
return server;
}
}
代码中为了保证线程安全,对服务器列表做了快照,但是这样又会引发新的问题,比如我们新增服务器或者某个服务器挂掉了,那么我们的轮询无法感知。
此外,代码中引入了重量级的同步方式synchronized,这样对与高并发量的业务来说,性能提高不上去。
2.随机算法
顾名思义,该算法就是每来一个请求,从后端服务器中随机地选择一个服务器处理请求,代码如下:
public static String testRandom() {
Set<String> keySet = serviceWeightMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();
keyList.addAll(keySet);
Random random = new Random();
int randomPos = random.nextInt(keyList.size());
String server = keyList.get(randomPos);
return server;
}
3.源地址哈希法
该方法是对客户端的IP地址做一个Hash,然后对服务器列表的大小取模,得到处理该请求的服务器
采用源地址哈希法进行负载均衡,相同的IP客户端,如果服务器列表不变,将映射到同一个后台服务器进行访问
public static String testConsumerHash(String remoteIp) {
Set<String> keySet = serviceWeightMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();
keyList.addAll(keySet);
int hashCode = remoteIp.hashCode();
int pos = hashCode % keyList.size();
return keyList.get(pos);
}
4.加权轮询法
该方法是在轮询的基础上加一个权重,权重高的服务器处理的请求就多:
public static String testWeightRoundRobin() {
Set<String> keySet = serviceWeightMap.keySet();
Iterator<String> it = keySet.iterator();
List<String> serverList = new ArrayList<String>();
while (it.hasNext()) {
String server = it.next();
Integer weight = serviceWeightMap.get(server);
for (int i=0; i<weight; i++) {
serverList.add(server);
}
Collections.shuffle(serverList);
}
String server = null;
synchronized (pos) {
if (pos > serverList.size()) {
pos = 0;
}
server = serverList.get(pos);
pos++;
}
return server;
}
5.加权随机法:
该算法是在随机算法的基础上加一个权重:
public static String testWeightRandom() {
Set<String> keySet = serviceWeightMap.keySet();
List<String> serverList = new ArrayList<String>();
Iterator<String> it = keySet.iterator();
while (it.hasNext()) {
String server = it.next();
Integer weight = serviceWeightMap.get(server);
for (int i=0; i<weight; i++) {
serverList.add(server);
}
}
Random random = new Random();
int randomPos = random.nextInt(serverList.size());
String server = serverList.get(randomPos);
return server;
}
6.最小连接法:
该算法是检测那一台服务器上的连接数最小,就将请求发给那一台服务器:
由于检测服务器上连接的代码较为复杂,这里先不列出
思路:先轮询一遍服务器列表,得到连接数最小的服务器,即为处理该请求的服务器