常见负载均衡算法

一、随机算法

1. 简单随机算法

思路:获取随机数,随机数不大于服务集合的容量,将该随机数当作下标,获取IP

// 服务IP集合
private static List<String> serverIps = Arrays.asList("A", "B", "C", "D", "E");

public static String random(){
    Random random = new Random();
    int i = random.nextInt(serverIps.size());
    return serverIps.get(i);
}

2. 加权随机算法

思路:创建一个新的List,将含有权重值得IP重新存入集合,权重是多少,就存多少个,然后使用随机算法从改集合中获取一个IP

public static String random() {
    // 含有权重的服务IP集合
    Map<String, Integer> map = new HashMap<>();
    map.put("A", 4);
    map.put("B", 6);
    map.put("C", 3);
    map.put("D", 2);
    map.put("E", 5);

    List<String> ips = new ArrayList<>();
    // 遍历map
    Set<Map.Entry<String, Integer>> entries = map.entrySet();
    for (Map.Entry<String, Integer> entry : entries) {
        // 服务IP
        String ip = entry.getKey();
        // 权重值
        Integer integer = entry.getValue();
        // 循环添加IP
        for (int i = 0; i<integer; i++){
            ips.add(ip);
        }
    }
    Random random = new Random();
    int i = random.nextInt(ips.size());
    return ips.get(i);
}

3.加权随机算法(优化)

思路:算法2中如果权重值过大,新建的List值就会很多,严重消耗内存,因此通过比较大小的方式确定随机数落在那个服务上;将各个服务的权重值看做数轴上的点,通过判断随机数落在那个区间内,从而确定选哪个服务

public static String random() {
    // 含有权重的服务IP集合
    Map<String, Integer> map = new HashMap<>();
    map.put("A", 4);
    map.put("B", 6);
    map.put("C", 3);
    map.put("D", 2);
    map.put("E", 5);

    // 总权重
    Integer totalWeigh = 0;
    Collection<Integer> values = map.values();
    for (Integer value : values) {
        totalWeigh += value;
    }
    // 获取随机数
    Random random = new Random();
    Integer pos = random.nextInt(totalWeigh);

    // 遍历含权重的服务集合
    for (String ip : map.keySet()) {
        // 获取IP权重值
        Integer integer = map.get(ip);

        // 如果随机数小于权重值,说明改随机数落在改服务上
        if (pos < integer) {
            return ip;
        }
        pos = pos - integer;
    }
    return "";
}


二、轮询算法

1. 简单轮询

思路1:设置全局下标,每次请求都+1

    // 服务IP集合
    private static List<String> serverIps = Arrays.asList("A", "B", "C", "D", "E");
    // 轮询下标
    private static int pos = 0;

    public static String roundRobin() {
        if (pos >= serverIps.size()) {
            pos = 0;
        }
        String ip = serverIps.get(pos);
        pos++;
        return ip;
    }

思路2:通过取模,获取下标

 // 服务IP集合
private static List<String> serverIps = Arrays.asList("A", "B", "C", "D", "E");
// 原子计数器
private static AtomicInteger atomicNum = new AtomicInteger(0);
    
public static String roundRobin() {
    int num = atomicNum.getAndAdd(1);
    int inx = num % serverIps.length;
    return serverIps[inx];
}

2. 加权轮询(List算法)

思路:创建新List,根据权重值将IP添加到新List中,然后通过简单轮询获取IP。
缺点:当权重值过大时,list过大,严重消耗内存

// 轮询下标
private static int pos = 0;

public static String roundRobin() {
    // 含有权重的服务IP集合
    Map<String, Integer> map = new HashMap<>();
    map.put("A", 4);
    map.put("B", 6);
    map.put("C", 3);
    map.put("D", 2);
    map.put("E", 5);

    List<String> ipList = new ArrayList<>();
    // 遍历map
    Set<Map.Entry<String, Integer>> entries = map.entrySet();
    for (Map.Entry<String, Integer> entry : entries) {
        // 服务IP
        String ip = entry.getKey();
        // 权重值
        Integer integer = entry.getValue();
        // 循环添加IP
        for (int i = 0; i < integer; i++) {
            ipList.add(ip);
        }
    }
    if (pos >= ipList.size()) {
        pos = 0;
    }
    String ip = ipList.get(pos);
    pos++;
    return ip;
}

3.加权轮询(取模坐标轴算法)

思路:记录请求次数,用请求次数模上总权重,然后判断该值落在坐标轴上的哪个范围

 /**
 * 请求计数器
 */
private static AtomicInteger atomicNum = new AtomicInteger(0);

public static String roundRobin() {
    // 含有权重的服务IP集合
    Map<String, Integer> map = new HashMap<>();
    map.put("A", 4);
    map.put("B", 6);
    map.put("C", 3);
    map.put("D", 2);
    map.put("E", 5);
    // 获取总权重
    Integer totalWeigh = 0;
    Collection<Integer> values = map.values();
    for (Integer value : values) {
        totalWeigh += value;
    }
    // 获取请求计数器值
    int pos = atomicNum.getAndAdd(1);
    // 取模
    int inx = pos % totalWeigh;
    // 循环判断,如果余数小于IP的权重值,就返回IP
    for (String ip : map.keySet()) {
        Integer weigh = map.get(ip);
        if (inx < weigh){
            return ip;
        }
        inx = inx - weigh;
    }
    return "";
}

4. 平滑加权轮询算法

思路:引入静态权重、动态权重概念

假设现在有3台服务:

服务器 | 权重 | 动态权重
—|--- | —
A | 5 | 0
B | 1 | 0
C | 1 | 0

  • IP
  • weigh --静态权重
  • currentWeigh --动态权重
算法介绍:
说明算法公式
1. 计算总权重totalWeightotalWeigh = weigh + … + weigh
2.计算currentWeigh值,初始为0currentWeigh = currentWeigh + weigh
3.获取currentweigh最大值MAX(currentWeigh )
4.返回IP返回currentweigh最大值对应的服务IP
5.修改最大权重值 currentWeigh - 总权重,其它不变MAX(currentWeigh ) - totalWeigh
运行结果:
运行次数计算currentWeigh值获取currentweigh最大值返回IP修改最大currentWeigh
15,1,15A-2,1,1
23,2,23A-4,2,2
31,3,33B1,-4,3
46,-3,46A-1,-3,4
54,-2,55C4,-2,-2
69,-1,-19A2,-1,-1
77,0,07A0,0,0

代码实例

  • 设置服务集合
/**
 * 服务
 */
public class ServerIp {
    // 含有权重的服务IP集合
    public static Map<String, Integer> serverMap = new HashMap<>();
    static {
        serverMap.put("A", 5);
        serverMap.put("B", 1);
        serverMap.put("C", 1);
    }
}
  • 封装权重对象
/**
 *  权重对象
 */
public class Weigh {

    /**
     *  服务IP
     */
    private String ip;
    /**
     * 静态权重
     */
    private Integer weigh;
    /**
     * 动态权重
     */
    private Integer currentWeigh;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getWeigh() {
        return weigh;
    }

    public void setWeigh(Integer weigh) {
        this.weigh = weigh;
    }

    public Integer getCurrentWeigh() {
        return currentWeigh;
    }

    public void setCurrentWeigh(Integer currentWeigh) {
        this.currentWeigh = currentWeigh;
    }

    public Weigh(String ip, Integer weigh, Integer currentWeigh) {
        this.ip = ip;
        this.weigh = weigh;
        this.currentWeigh = currentWeigh;
    }
  • 负载算法
public class RoundRobin {

    // 服务集合
    private static List<Weigh> weighList = new ArrayList<>();

    // 总权重
    private static Integer totalWeigh = 0;

    public static String getServer() {
        // 1、初始化Weigh对象,currentWeigh值设置为0
        if (weighList.isEmpty()) {
            ServerIp.serverMap.forEach((ip, weigh) -> {
                Weigh w = new Weigh(ip, weigh, 0);
                weighList.add(w);
                totalWeigh +=weigh;
            });
        }
        // 2、循环计算currentWeigh值,公式:currentWeigh = weigh + currentWeigh
        for (Weigh weigh : weighList) {
            weigh.setCurrentWeigh(weigh.getWeigh() + weigh.getCurrentWeigh());
        }
        // 3、获取currentweigh最大值
        Weigh maxWeigh = null;
        for (Weigh weigh : weighList) {
            if (maxWeigh == null || weigh.getCurrentWeigh() > maxWeigh.getCurrentWeigh()) {
                maxWeigh = weigh;
            }
        }
        // 修改最大权重值,公式:currentWeigh - 总权重
        maxWeigh.setCurrentWeigh(maxWeigh.getCurrentWeigh() - totalWeigh);
        return maxWeigh.getIp();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值