欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-15 18:56:05
加权轮询算法:不同的后端服务器,在机器的配置和当前系统的负载方面,可能并不相同。因此,它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请求;给配置低、负载高的机器分配较低的权重,降低系统负载。加权轮询算法能很好地处理这一问题,并将请求顺序地按照权重分配到后端服务器。一、算法描述假设有 N 台服务器 S = {S0, S1, S2, …, Sn},默认权重为 W = {W0, W1, W2, …, Wn},服务器列表为 serverList,算法可以描述为:1、初始化 s...

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

一、算法描述

假设有 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.1 1
192.168.1.2 2
192.168.1.3 3
192.168.1.4 4

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

服务器地址 序号
192.168.1.1 1
192.168.1.2 2
192.168.1.2 3
192.168.1.3 4
192.168.1.3 5
192.168.1.3 6
192.168.1.4 7
192.168.1.4 8
192.168.1.4 9
192.168.1.4 10

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

二、java代码实现

package com.test.mvp.schedulealgothrim;

import com.google.common.collect.SortedMultiset;
import com.google.common.collect.TreeMultiset;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;

class Server implements Serializable {
    private static final long serialVersionUID = 7246747589293111189L;

    private String server;
    private Integer weight;
    private String description;

    public Server(String server, String description, Integer weight) {
        this.server = server;
        this.description = description;
        this.weight = weight;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }


    public String getServer() {
        return server;
    }

    public void setServer(String server) {
        this.server = server;
    }

    public Integer getWeight() {
        return weight;
    }

    public void setWeight(Integer weight) {
        this.weight = weight;
    }
}

class ServerManager {
    public static Map<String, Server> serverMap = new TreeMap<>();

    static {
        serverMap.put("192.168.1.1", new Server("192.168.1.1", "第1台server", 1));
        serverMap.put("192.168.1.2", new Server("192.168.1.2", "第2台server", 2));
        serverMap.put("192.168.1.3", new Server("192.168.1.3", "第3台server", 3));
        serverMap.put("192.168.1.4", new Server("192.168.1.4", "第4台server", 4));
    }
}

class WeightRoundRobin {
    private static AtomicInteger indexAtomic = new AtomicInteger(0);
    private static ArrayList<String> middleServerList;

    public static void computeMiddleServerList() {
        ArrayList<String> serverList = new ArrayList<>();
        Set<String> serverSet = ServerManager.serverMap.keySet();
        for (String server : serverSet) {
            Integer weight = ServerManager.serverMap.get(server).getWeight();
            for (int i = 0; i < weight; i++) {
                serverList.add(server);
            }
        }
        middleServerList = serverList;
    }

    public static String getServer() {
        if (CollectionUtils.isEmpty(middleServerList)) {
            computeMiddleServerList();
            System.out.println("compute Middle Server List");
        }
        if (indexAtomic.get() >= middleServerList.size()) {
            indexAtomic.set(0);
        }
        return middleServerList.get(indexAtomic.getAndIncrement());
    }
}

public class WeightRoundRobinTest {
    public static void main(String[] args) {
        SortedMultiset<String> serverSet = TreeMultiset.create();
        for (int i = 0; i < 100; i++) {
            String server = WeightRoundRobin.getServer();
            Server curServer = ServerManager.serverMap.get(server);
            System.out.println(server + ", " + curServer.getDescription() + ", weight=" + curServer.getWeight());
            serverSet.add(server, 1);
        }

        ServerManager.serverMap.forEach((key, value)->{
            System.out.println(key + ", count:" + serverSet.count(key));
        });
    }
}

运行结果如下所示:

compute Middle Server List
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, 第1台server, weight=1
192.168.1.2, 第2台server, weight=2
192.168.1.2, 第2台server, weight=2
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.3, 第3台server, weight=3
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.4, 第4台server, weight=4
192.168.1.1, count:10
192.168.1.2, count:20
192.168.1.3, count:30
192.168.1.4, count:40

说明:

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

本文地址:https://blog.csdn.net/chinawangfei/article/details/109593274