几种负载均衡算法简介

首先我们来看一下什么是负载均衡?

随着业务的发展,单台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.最小连接法:
该算法是检测那一台服务器上的连接数最小,就将请求发给那一台服务器:
由于检测服务器上连接的代码较为复杂,这里先不列出
思路:先轮询一遍服务器列表,得到连接数最小的服务器,即为处理该请求的服务器

猜你喜欢

转载自blog.csdn.net/qq_37043780/article/details/82714830