面试官:负载均衡的算法你了解不?

shajm 2019-12-25

上一篇文章我讲了关于负载均衡的三种算法,轮询法,随机法,最小连接法,这三种负载均衡的算法,但是关于负载均衡还有其他的算法,我们也需要你去看,而且在面试的过程中,很有可能是会问到的呦。

面试官:负载均衡的算法你了解不?

对于要实现高性能集群,选择好负载均衡器很重要,同时针对不同的业务场景选择合适的负载均衡算法也是非常重要的。之前已经罗列出几个了,接下来在说剩下的几个算法,

1. 源地址哈希算法

唯一不丢失策略的算法,但是负载均衡和源数据信息和哈希算法有很大关系。

源地址哈希法的思想是根据服务消费者请求客户端的 IP 地址,通过哈希函数计算得到一个哈希值,将此哈希值和服务器列表的大小进行取模运算,得到的结果便是要访问的服务器地址的序号。采用源地址哈希法进行负载均衡,相同的 IP 客户端,如果服务器列表不变,将映射到同一个后台服务器进行访问。

还是之前的操作,伪代码:

private static Map<String, Integer> serviceWeightMap = new HashMap<String, Integer>(); 
 
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); 
   } 
 
   public static String testConsumerHash(String remoteIp) { 
 
       Map<String, Integer> serverMap = new HashMap<String, Integer>(); 
       serverMap.putAll(serviceWeightMap); 
 
       //取得IP地址list 
       Set<String> keySet = serverMap.keySet(); 
       ArrayList<String> keyList = new ArrayList<String>(); 
       keyList.addAll(keySet); 
 
       int hashCode = remoteIp.hashCode(); 
       int pos = hashCode % keyList.size(); 
 
       return keyList.get(pos); 
   } 

这段代码来自 Will.Shun 所写,我当时看到的时候也不是很明白什么意思,后来看了一下,其实和它的解释很类似,通过哈希函数计算得到一个哈希值,将此哈希值和服务器列表的大小进行取模运算,得到的结果便是要访问的服务器地址的序号。

2. 加权轮询算法

再来看一下加权轮训算法,我们先看一下在 Nginx 里面进行的权重配置:

http { 
upstream cluster { 
server a weight=1; 
server b weight=2; 
server c weight=3; 
} 

假如 Nginx 每收到 6 个客户端的请求,会把其中的 1 个转发给后端 a,把其中的 2 个转发给后端 b,把其中的 3 个转发给后端 c。

加权轮询算法的结果,就是要生成一个服务器序列。每当有请求到来时,就依次从该序列中取出下一个服务器用于处理该请求。

加权轮训算法伪代码:

private static Map<String, Integer> serviceWeightMap = new HashMap<String, Integer>(); 
 
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); 
   } 
 
 
    public static String testWeightRoundRobin() { 
 
        // 重新创建一个map,避免出现由于服务器上线和下线导致的并发问题 
        Map<String, Integer> serverMap = new HashMap<String, Integer>(); 
        serverMap.putAll(serviceWeightMap); 
 
        //取得IP地址list 
        Set<String> keySet = serverMap.keySet(); 
        Iterator<String> it = keySet.iterator(); 
 
        List<String> serverList = new ArrayList<String>(); 
 
        while (it.hasNext()) { 
            String server = it.next(); 
            Integer weight = serverMap.get(server); 
            for (int i=0; i<weight; i++) { 
                serverList.add(server); 
            } 
        } 
 
        String server = null; 
 
        synchronized (pos) { 
            if (pos > serverList.size()) { 
                pos = 0; 
            } 
 
            server = serverList.get(pos); 
            pos++; 
        } 
 
        return server; 
} 

其实在 加权轮训算法中,是有缺陷的,在某些特殊的权重下,加权轮询调度会生成不均匀的实例序列,这种不平滑的负载可能会使某些实例出现瞬时高负载的现象,导致系统存在宕机的风险。而为了解决这个调度的缺陷,后边就有平滑加权轮训调度,有兴趣的同学一定要去看一下这个平滑加权轮训。

3. 加权随机算法

加权随机法跟加权轮询法类似,根据后台服务器不同的配置和负载情况,配置不同的权重。不同的是,它是按照权重来随机选取服务器的,而非顺序。

private static Map<String, Integer> serviceWeightMap = new HashMap<String, Integer>(); 
 
    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); 
       } 
 
    public static String testWeightRandom() { 
        // 重新创建一个map,避免出现由于服务器上线和下线导致的并发问题 
        Map<String, Integer> serverMap = new HashMap<String, Integer>(); 
        serverMap.putAll(serviceWeightMap); 
 
        //取得IP地址list 
        Set<String> keySet = serverMap.keySet(); 
        List<String> serverList = new ArrayList<String>(); 
        Iterator<String> it = keySet.iterator(); 
 
        while (it.hasNext()) { 
            String server = it.next(); 
            Integer weight = serverMap.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; 
    } 

这里不同的地方就是服务器是通过随机算法获取。

其实我们可以想一个实例:比如说在以下场景:有一个集合 S,里面比如有 A,B,C,D 这四项。这时我们想随机从中抽取一项,但是抽取的概率不同,比如我们希望抽到 A 的概率是 50%,抽到 B 和 C 的概率是 20%,D 的概率是 10%。一般来说,我们可以给各项附一个权重,抽取的概率正比于这个权重。

4.HTTP 国际化

HTTP 报文中可以承载以任何语言表示的内容,就像它能承载图像、影片,或任何类型的 媒体那样。对 HTTP 来说,实体主体只是二进制信息的容器而已。

为了支持国际性的内容,服务器需要告知客户端每个文档的字母表和语言,这样客户端才 能正确地把文档中的信息解包为字符并把内容呈现给用户。

相关推荐