负载均衡算法--加权轮询法(Weight Round Robin)

Posted 志波同学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了负载均衡算法--加权轮询法(Weight Round Robin)相关的知识,希望对你有一定的参考价值。

接上一篇博文:负载均衡算法–轮询法(Round Robin),本文讲解加权轮询算法。

加权轮询算法:不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请求;给配置低、负载高的机器分配较低的权重,降低系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。

算法描述

假设有 N 台服务器 S = S0, S1, S2, …, Sn,默认权重为 W = W0, W1, W2, …, Wn,服务器列表为 serverList,算法可以描述为:
1、初始化 serverList,将 W0 个 S0 加入至serverList,将 W1 个 S1 加入至serverList,依据此规则将所有的服务器加入至 serverList 中;
2、从 serverList 的从 S0 开始依序调度;
3、若所有服务器都已被调度过,则从头开始调度;

假定我们现在有如下四台服务器:

服务器地址权重
192.168.1.11
192.168.1.22
192.168.1.33
192.168.1.44

初始化服务列表后, serverList 如下:

服务器地址序号
192.168.1.11
192.168.1.22
192.168.1.23
192.168.1.34
192.168.1.35
192.168.1.36
192.168.1.47
192.168.1.48
192.168.1.49
192.168.1.410

加权轮训算法通过在服务器列表中增加相应的权重个数的服务器来达到加权的效果,每个服务器会依序被轮训到。

代码实现

1、服务器管理类

package org.learn.loadbalance;

import java.util.Map;
import java.util.TreeMap;

/**
 * @author zhibo
 * @date 2019/5/16 16:25
 */
public class ServerManager 
    public volatile static Map<String, Integer> serverMap = new TreeMap<>();

    static 
        serverMap.put("192.168.1.1", 1);
        serverMap.put("192.168.1.2", 2);
        serverMap.put("192.168.1.3", 3);
        serverMap.put("192.168.1.4", 4);
    


2、加权轮询类

package org.learn.loadbalance;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhibo
 * @date 2019/5/16 16:28
 */
public class WeightRoundRobin 
    private static AtomicInteger indexAtomic = new AtomicInteger(0);

    public static String getServer() 
        ArrayList<String> serverList = new ArrayList<>();
        Set<String> serverSet = ServerManager.serverMap.keySet();
        Iterator<String> iterator = serverSet.iterator();
        while(iterator.hasNext())
            String server = iterator.next();
            Integer weight = ServerManager.serverMap.get(server);
            for (int i = 0; i < weight; i++) 
                serverList.add(server);
            
        

        if (indexAtomic.get() >= serverList.size()) 
            indexAtomic.set(0);
        
        String server = serverList.get(indexAtomic.getAndIncrement());
        return server;
    

    public static void main(String[] args) 
        for (int i = 0; i < 20; i++) 
            String server = getServer();
            System.out.println(server);
        
    


1、使用 AtomicInteger 进行轮询索引的增减,保证并发的安全性。
2、在多线程的情况下, 线程A修改 ServerManager.serverMap 的值,线程B无法即时拿到线程A修改后的值,因此可能会产生请求错误,需要调用端进行容错处理。
3、从宏观的角度讲,权重高的服务器被访问的次数高一些,近似均衡;微观的角度讲,权重高的服务器会被连续访问到,看起来没有那么均衡。

执行 main 方法输出结果如下:

文章内容仅代表个人观点,如有不正之处,欢迎批评指正,谢谢大家。

以上是关于负载均衡算法--加权轮询法(Weight Round Robin)的主要内容,如果未能解决你的问题,请参考以下文章

负载均衡算法--加权随机法(Weight Random)

Dubbo加权轮询负载均衡算法应用之推荐产品

数据结构和算法 负载均衡算法

干货 | JAVA面试题(架构篇)

负载均衡算法--源地址哈希法(Hash)

负载均衡之加权轮询算法(转)