负载均衡

负载均衡

​ 多台服务器组成一台服务器集合,每台服务器都具有等价的地位, 可以单独提供服务且无需其他服务器的辅助,通过某种负载分担技术,将外部发送来的请求 均衡的分配到服务器集合中的每一台服务器上,而接受到请求的服务器独立的回应客户请求。

​ 负载均衡是高可用网络基础架构的一个关键组成部分, 有了负载均衡,我们通常可以将我们的应用服务器部署多个,然后通过负载均衡将用户的请求发送到不同的服务器来提高网站,应用,数据库或者其他服务的性能以及可靠性。

​ 正常情况下多个用户通过网络 访问单个服务器,数据库处理数据,如果出现服务器宕机的情况的话,在只有一个服务器的下,用户的请求就会得不到回应(单点故障问题),又或者N个用户在段时间内访问同一服务器,超过了服务器的处理能力,会产生响应速度慢 甚至无法连接到服务器的情况。

负载均衡方案

​ 通过一个负载均衡器、至少两个web服务器、由 均衡器根据业务逻辑(比如:某个服务器通过运行状态检查服务检查此服务器已经宕机,将不分配用户请求给此服务器,直至检查服务器状态为”健康”在将用户请求发送给此服务器。)分配用户请求转发至某个服务器。

算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ip列表
public class ipMap {
public static HashMap<String, Integer> serverWeightMap = new HashMap<String, Integer>();
static {
serverWeightMap.put("192.168.1.100", 1);
serverWeightMap.put("192.168.1.101", 1);
// 权重为4
serverWeightMap.put("192.168.1.102", 4);
serverWeightMap.put("192.168.1.103", 1);
serverWeightMap.put("192.168.1.104", 1);
// 权重为3
serverWeightMap.put("192.168.1.105", 3);
serverWeightMap.put("192.168.1.106", 1);
// 权重为2
serverWeightMap.put("192.168.1.107", 2);
serverWeightMap.put("192.168.1.108", 1);
serverWeightMap.put("192.168.1.109", 1);
serverWeightMap.put("192.168.1.110", 1);
}
}
随机

向集合中添加负载地址 加权 添加单个负载地址个数 随机负载个数,循环转发请求到服务器上,次数足够多的的情况下,每个负载地址根据权重所接受的请求次数 与集合长度是成比例的。

  • 优点:使用简单
  • 缺点:不适合机器配置不同的场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static String random() {
// 重建一个Map,避免服务器的上下线导致的并发问题
Map<String, Integer> serverMap = new HashMap<String, Integer>();
serverMap.putAll(ipMap.serverWeightMap);

// 取得Ip地址List
Set<String> keySet = serverMap.keySet();
Iterator<String> iterator = keySet.iterator();

List<String> serverList = new ArrayList<String>();
while (iterator.hasNext()) {
String server = iterator.next();
int weight = serverMap.get(server);
for (int i = 0; i < weight; i++)
serverList.add(server);
}
java.util.Random random = new java.util.Random();
int randomPos = random.nextInt(serverList.size());
return serverList.get(randomPos);
}
轮询

为第一个请求选择健康池中的第一个后端服务器,然后按顺序往后依次选择,直到最后一个,然后循环。

  • 优点:服务器请求数目相同
  • 缺点:服务器压力不一致,不合适服务器配置不同的情况;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static String pollingIp() {
// 重建一个Map,避免服务器的上下线导致的并发问题
Map<String, Integer> serverMap = new HashMap<String, Integer>();
serverMap.putAll(ipMap.serverWeightMap);

// 取得Ip地址List
Set<String> keySet = serverMap.keySet();
Iterator<String> iterator = keySet.iterator();

List<String> serverList = new ArrayList<String>();
while (iterator.hasNext()) {
String server = iterator.next();
int weight = serverMap.get(server);
/*循环获取map 中的key 的value 是多少 放入list中 */
for (int i = 0; i < weight; i++)
serverList.add(server);
}
String server = null;
synchronized (pos) {
if (pos > keySet.size())
pos = 0;
server = serverList.get(pos);
pos ++;
}
return server;
}
最小连接

最小连接数算法比较灵活和智能,由于后端服务器的配置不尽相同,对于请求的处理有 快有慢,它正是根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前请求,尽可能地提高后端服务器的利用效率,将负载 合理地分流到每一台机器。由于最小连接数设计服务器连接数的汇总和感知,设计与实现较为繁琐。

  • 优点:根据服务器当前的情况处理请求,动态分配
  • 缺点:算法实现相对复杂,需要监控服务器请求连接数;
散列

根据请求源的某一值(IP)的散列(hash)来选择要转发的服务器。这种方式可以一定程度上保证特定用户能连接到相同的服务器。如果你的应用需要处理状态而要求用户能连接到和之前相同的服务器,可以考虑采取这种方式。

  • 优点:将来自同一ip地址的请求,同一会话期内,转发到相同的服务器,直到后端服务器列表变更, 根据此特性 可以在服务先飞这与服务提供者之间建立有状态的session会话 实现会话粘贴。
  • 缺点:某一目标服务器宕机后,当前服务器会话消失,出现hash倾斜

出现hash倾斜的解决方案:虚拟节点,在真实的服务器节点之间 添加 添加服务器节点映射(虚拟节点)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static String hash(String remoteIp){
// 重建一个Map,避免服务器的上下线导致的并发问题
Map<String, Integer> serverMap = new HashMap<String, Integer>();
serverMap.putAll(ipMap.serverWeightMap);

// 取得Ip地址List
Set<String> keySet = serverMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();
keyList.addAll(keySet);

// 在Web应用中可通过HttpServlet的getRemoteIp方法获取
//String remoteIp = "127.0.0.1";

int hashCode = remoteIp.hashCode();
int serverListSize = keyList.size();
int serverPos = hashCode % serverListSize;

return keyList.get(serverPos);
}
实际运用

实际项目中的话肯定是多个均衡算法糅合在一起实现。

分享到