7种常见的生产级负载均衡算法

news2024/11/17 11:30:21

准备测试数据

package com.example.demo.balance;

import java.util.*;

/**
 * @author liwenchao
 */
public class ServerIps {
    public static final List<String> LIST = Arrays.asList(
            "192.168.0.1",
            "192.168.0.2",
            "192.168.0.3",
            "192.168.0.4",
            "192.168.0.5",
            "192.168.0.6",
            "192.168.0.7",
            "192.168.0.8",
            "192.168.0.9",
            "192.168.0.10"
    );

    public static final Map<String, Integer> WEIGHT_LIST = new HashMap<String, Integer>();

    static {
        // 权重之和为50
        WEIGHT_LIST.put("192.168.0.1", 1);
        WEIGHT_LIST.put("192.168.0.2", 8);
        WEIGHT_LIST.put("192.168.0.3", 3);
        WEIGHT_LIST.put("192.168.0.4", 6);
        WEIGHT_LIST.put("192.168.0.5", 5);
        WEIGHT_LIST.put("192.168.0.6", 5);
        WEIGHT_LIST.put("192.168.0.7", 4);
        WEIGHT_LIST.put("192.168.0.8", 7);
        WEIGHT_LIST.put("192.168.0.9", 2);
        WEIGHT_LIST.put("192.168.0.10", 9);
    }

    public static final Map<String, Integer> WEIGHT_ROUND_ROBIN_LIST = new HashMap<String, Integer>();

    static {
        WEIGHT_ROUND_ROBIN_LIST.put("192.168.0.1", 5);
        WEIGHT_ROUND_ROBIN_LIST.put("192.168.0.2", 1);
        WEIGHT_ROUND_ROBIN_LIST.put("192.168.0.3", 1);
    }

    /**
     * 服务器当前的活跃数
     */
    public static final Map<String, Integer> ACTIVITY_LIST = new LinkedHashMap<String, Integer>();

    static {
        ACTIVITY_LIST.put("192.168.0.1", 2);
        ACTIVITY_LIST.put("192.168.0.2", 0);
        ACTIVITY_LIST.put("192.168.0.3", 1);
        ACTIVITY_LIST.put("192.168.0.4", 3);
        ACTIVITY_LIST.put("192.168.0.5", 0);
        ACTIVITY_LIST.put("192.168.0.6", 1);
        ACTIVITY_LIST.put("192.168.0.7", 4);
        ACTIVITY_LIST.put("192.168.0.8", 2);
        ACTIVITY_LIST.put("192.168.0.9", 7);
        ACTIVITY_LIST.put("192.168.0.10", 3);
    }
}

1,随机算法-RandomLoadBalance

package com.example.demo.balance;

import java.util.Random;

/**
 * 随机算法
 *
 * @author liwenchao
 */
public class RandomLoadBalance {

    public static String getServer() {
        // 生成一个随机数作为list的下标值
        Random random = new Random();
        int randomPos = random.nextInt(ServerIps.LIST.size());
        return ServerIps.LIST.get(randomPos);
    }

    public static void main(String[] args) {
        // 连续调用10次
        for (int i = 0; i < 10; i++) {
            System.out.println(getServer());
        }
    }

}

运行结果

192.168.0.8
192.168.0.6
192.168.0.6
192.168.0.6
192.168.0.9
192.168.0.3
192.168.0.9
192.168.0.1
192.168.0.1
192.168.0.3

当调用次数比较少时,Random 产生的随机数可能会比较集中,此时多数请求会落到同一台服务器上,只有在经过多次请求后,才能使调用请求进行“均匀”分配。调用量少这一点并没有什么关系,负载均衡机制不正是为了应对请求量多的情况吗,所以随机算法也是用得比较多的一种算法。

但是,上面的随机算法适用于每天机器的性能差不多的时候,实际上,生产中可能某些机器的性能更高一点,它可以处理更多的请求,所以,我们可以对每台服务器设置一个权重。
在ServerIps类中增加服务器权重对应关系MAP,权重之和为50。

那么现在的随机算法应该要改成权重随机算法,当调用量比较多的时候,服务器使用的分布应该近似对应权重的分布。

2,权重随机算法-RoundRobinLoadBalance

简单的实现思路是,把每个服务器按它所对应的服务器进行复制,具体看代码更加容易理解

package com.example.demo.balance;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 权重随机算法
 *
 * @author liwenchao
 */
public class WeightRandomLoadBalance {

    public static String getServer() {
        //生成一个随机数作为list的下标值
        List<String> ips = new ArrayList<>();
        for (String ip : ServerIps.WEIGHT_LIST.keySet()) {
            Integer weight = ServerIps.WEIGHT_LIST.get(ip);
            //按权重进行复制
            for (int i = 0; i < weight; i++) {
                ips.add(ip);
            }
        }
        Random random = new Random();
        int randomPos = random.nextInt(ips.size());
        return ips.get(randomPos);
    }

   
    public static void main(String[] args) {
        // 连续调用10次
        for (int i = 0; i < 10; i++) {
            System.out.println(getServer());
        }
    }
}

执行结果

192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
192.168.0.10
192.168.0.1

这种实现方法在遇到权重之和特别大的时候就会比较消耗内存,因为需要对ip地址进行复制,权重之和越大那么上文中的ips就需要越多的内存,下面介绍另外一种实现思路。
假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上。比如数字3会落到服务器 A 对应的区间上,此时返回服务器 A 即可。权重越大的机器,在坐标轴上对应的区间范围就越大,因此随机数生成器生成的数字就会有更大的概率落到此区间内。只要随机数生成器产生的随机数分布性很好,在经过多次选择后,每个服务器被选中的次数比例接近其权重比例。比如,经过一万次选择后,服务器 A 被选中的次数大约为5000次,服务器 B 被选中的次数约为3000次,服务器 C 被选中的次数约为2000次。
假设现在随机数offset=7:

1offset<5 is false,所以不在[0, 5)区间,将offset = offset - 5(offset=2)
2offset<3 is true,所以处于[5, 8)区间,所以应该选用B服务器 实现如下:

package com.example.demo.balance;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 权重随机算法
 *
 * @author liwenchao
 */
public class WeightRandomLoadBalance {


    public static String getServer() {
        int totalWeight = 0;
        //如果所有权重都相等,那么随机一个ip就好了
        boolean sameWeight = true;
        Object[] weights = ServerIps.WEIGHT_LIST.values().toArray();
        for (int i = 0; i < weights.length; i++) {
            Integer weight = (Integer) weights[i];
            totalWeight += weight;
            if (sameWeight && i > 0 && !weight.equals(weights[i - 1])) {
                sameWeight = false;
            }
        }
        Random random = new Random();
        int randomPos = random.nextInt(totalWeight);
        if (!sameWeight) {
            for (String ip : ServerIps.WEIGHT_LIST.keySet()) {
                Integer value = ServerIps.WEIGHT_LIST.get(ip);
                if (randomPos < value) {
                    return ip;
                }
                randomPos = randomPos - value;
            }
        }
        return (String) ServerIps.WEIGHT_LIST.keySet().toArray()[new Random().nextInt(ServerIps.WEIGHT_LIST.size())];
    }

    public static void main(String[] args) {
        // 连续调用10次
        for (int i = 0; i < 10; i++) {
            System.out.println(getServer());
        }
    }
}

这就是另外一种权重随机算法。

3,轮询算法-RoundRobinLoadBalance

package com.example.demo.balance;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author liwenchao
 */
public class RoundRobinLoadBalance {

    /**
     * 当前循环的位置
     */
    private static final AtomicInteger POS = new AtomicInteger(0);

    public static String getServer() {
        if (POS.get() >= ServerIps.LIST.size()) {
            POS.set(0);
        }
        return ServerIps.LIST.get(POS.getAndIncrement());
    }

    public static void main(String[] args) {
        // 连续调用10次
        for (int i = 0; i < 11; i++) {
            System.out.println(getServer());
        }
    }


}

执行结果

192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
192.168.0.10
192.168.0.1

这种算法很简单,也很公平,每台服务轮流来进行服务,但是有的机器性能好,所以能者多劳,和随机算法一下,加上权重这个维度之后,其中一种实现方法就是复制法,这里就不演示了,这种复制算法的缺点和随机算法的是一样的,比较消耗内存,那么自然就有其他实现方法。

4,权重轮询算法-WeightRoundRobinLoadBalance

这种算法需要加入一个概念:调用编号,比如第1次调用为1, 第2次调用为2, 第100次调用为100,调用编号是递增的,所以我们可以根据这个调用编号推算出服务器。
假设我们有三台服务器 servers = [A, B, C],对应的权重为 weights = [ 2, 5, 1], 总权重为8,我们可以理解为有8台“服务器”,这是8台“不具有并发功能”,其中有2台为A,5台为B,1台为C,一次调用过来的时候,需要按顺序访问,比如有10次调用,那么服务器调用顺序为AABBBBBCAA,调用编号会越来越大,而服务器是固定的,所以需要把调用编号“缩小”,这里对调用编号进行取余,除数为总权重和,比如:

1号调用,1%8=1;
2号调用,2%8=2;
3号调用,3%8=3;
8号调用,8%8=0;
9号调用,9%8=1;
100号调用,100%8=4; 我们发现调用编号可以被缩小为0-7之间的8个数字,问题是怎么根据这个8个数字找到对应的服务器呢?和我们随机算法类似,这里也可以把权重想象为一个坐标轴

“0-----2-----7-----8”

1号调用,1%8=1,offset = 1, offset <= 2 is true,取A;
2号调用,2%8=2;offset = 2,offset <= 2 is true, 取A;
3号调用,3%8=3;offset = 3, offset <= 2 is false, offset = offset - 2, offset = 1, offset <= 5,取B
8号调用,8%8=0;offset = 0, 特殊情况,offset = 8,offset <= 2 is false, offset = offset - 2, offset = 6, offset  <= 5 is false, offset = offset - 5, offset = 1, offset <= 1 is true, 取C;
9号调用,9%8=1;// ...
100号调用,100%8=4; //...

package com.example.demo.balance;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author liwenchao
 */
public class WeightRoundRobinLoadBalance {

    private static final AtomicInteger POS = new AtomicInteger(0);

    public static String getServer() {
        int totalWeight = 0;
        //如果所有权重都相等,那么随机一个ip就好了
        boolean sameWeight = true;
        Object[] weights = ServerIps.WEIGHT_LIST.values().toArray();
        for (int i = 0; i < weights.length; i++) {
            Integer weight = (Integer) weights[i];
            totalWeight += weight;
            if (sameWeight && i > 0 && !weight.equals(weights[i - 1])) {
                sameWeight = false;
            }
        }
        int sequenceNum = POS.getAndIncrement();
        int offset = sequenceNum % totalWeight;
        offset = offset == 0 ? totalWeight : offset;
        if (!sameWeight) {
            for (String ip : ServerIps.WEIGHT_LIST.keySet()) {
                Integer weight = ServerIps.WEIGHT_LIST.get(ip);
                if (offset <= weight) {
                    return ip;
                }
                offset = offset - weight;
            }
        }
        if (sequenceNum >= ServerIps.WEIGHT_LIST.size() - 1) {
            POS.set(0);
        }
        return (String) ServerIps.WEIGHT_LIST.keySet().toArray()[sequenceNum];
    }

    public static void main(String[] args) {
        // 连续调用11次
        for (int i = 0; i < 12; i++) {
            System.out.println(getServer());
        }
    }

}

执行结果

192.168.0.7
192.168.0.2
192.168.0.2
192.168.0.2
192.168.0.2
192.168.0.2
192.168.0.2
192.168.0.2
192.168.0.2
192.168.0.1
192.168.0.4
192.168.0.4

但是这种算法有一个缺点:一台服务器的权重特别大的时候,他需要连续的的处理请求,但是实际上我们想达到的效果是,对于100次请求,只要有100*8/50=16次就够了,这16次不一定要连续的访问,比如假设我们有三台服务器 servers = [A, B, C],对应的权重为 weights = [5, 1, 1] , 总权重为7,那么上述这个算法的结果是:AAAAABC,那么如果能够是这么一个结果呢:AABACAA,把B和C平均插入到5个A中间,这样是比较均衡的了。

我们这里可以改成平滑加权轮询。

5,平滑加权轮询算法-WeightRoundSmoothRobinLoadBalance

思路:每个服务器对应两个权重,分别为 weight 和 currentWeight。其中 weight 是固定的,currentWeight 会动态调整,初始值为0。当有新的请求进来时,遍历服务器列表,让它的 currentWeight 加上自身权重。遍历完成后,找到最大的 currentWeight,并将其减去权重总和,然后返回相应的服务器即可。

请求编号

currentWeight 数组 (current_weight += weight)

选择结果(max(currentWeight))

减去权重总和后的currentWeight 数组(max(currentWeight) -= sum(weight))

1

[5, 1, 1]

A

[-2, 1, 1]

2

[3, 2, 2] 

A

[-4, 2, 2]

3

[1, 3, 3]

B

[1, -4, 3]

4

[6, -3, 4]

A

[-1, -3, 4]

5

[4, -2, 5]

C

[4, -2, -2]

6

[9, -1, -1]

A

[2, -1, -1]

7

[7, 0, 0]

A

[0, 0, 0]

如上,经过平滑性处理后,得到的服务器序列为 [A, A, B, A, C, A, A],相比之前的序列 [A, A, A, A, A, B, C],分布性要好一些。初始情况下 currentWeight = [0, 0, 0],第7个请求处理完后,currentWeight 再次变为 [0, 0, 0]。

package com.example.demo.balance;

/**
 * 增加一个Weight类,用来保存ip, weight(固定不变的原始权重), currentWeight(当前会变化的权重)
 */
public class Weight {

    private String ip;
    private Integer weight;
    private Integer currentWeight;

    public Weight(String ip, Integer weight, Integer currentWeight) {
        this.ip = ip;
        this.weight = weight;
        this.currentWeight = currentWeight;
    }

    public String getIp() {
        return ip;
    }

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

    public Integer getWeight() {
        return weight;
    }

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

    public Integer getCurrentWeight() {
        return currentWeight;
    }

    public void setCurrentWeight(Integer currentWeight) {
        this.currentWeight = currentWeight;
    }
}
package com.example.demo.balance;

import java.util.HashMap;
import java.util.Map;

/**
 * @author liwenchao
 */
public class WeightRoundSmoothRobinLoadBalance {

    private static Map<String, Weight> weightMap = new HashMap<>();

    public static String getServer() {
        int totalWeight = ServerIps.WEIGHT_ROUND_ROBIN_LIST.values().stream().reduce(0, Integer::sum);
        //初始化weightMap,初始时将currentWeight赋值为weight
        if (weightMap.isEmpty()) {
            ServerIps.WEIGHT_ROUND_ROBIN_LIST.forEach((key, value) -> {
                weightMap.put(key, new Weight(key, value, value));
            });
        }
        // 找出currentWeight最大值
        Weight maxCurrentWeight = null;
        for (Weight weight : weightMap.values()) {
            if (maxCurrentWeight == null || weight.getCurrentWeight() > maxCurrentWeight.getCurrentWeight()) {
                maxCurrentWeight = weight;
            }
        }
        // 将maxCurrentWeight减去总权重和
        maxCurrentWeight.setCurrentWeight(maxCurrentWeight.getCurrentWeight() - totalWeight);
        // 所有的ip的currentWeight统一加上原始权重
        for (Weight weight : weightMap.values()) {
            weight.setCurrentWeight(weight.getCurrentWeight() + weight.getWeight());
        }
        // 返回maxCurrentWeight所对应的ip
        return maxCurrentWeight.getIp();
    }

    public static void main(String[] args) {
        // 连续调用10次
        for (int i = 0; i < 10; i++) {
            System.out.println(getServer());
        }
    }

}

执行结果

192.168.0.1
192.168.0.1
192.168.0.2
192.168.0.1
192.168.0.3
192.168.0.1
192.168.0.1
192.168.0.1
192.168.0.1
192.168.0.2

这就是轮询算法,一个循环很简单,但是真正在实际运用的过程中需要思考更多。

6,一致性哈希算法-ConsistentHashLoadBalance

服务器集群接收到一次请求调用时,可以根据根据请求的信息,比如客户端的ip地址,或请求路径与请求参数等信息进行哈希,可以得出一个哈希值,特点是对于相同的ip地址,或请求路径和请求参数哈希出来的值是一样的,只要能再增加一个算法,能够把这个哈希值映射成一个服务端ip地址,就可以使相同的请求(相同的ip地址,或请求路径和请求参数)落到同一服务器上。
因为客户端发起的请求情况是无穷无尽的(客户端地址不同,请求参数不同等等),所以对于的哈希值也是无穷大的,所以我们不可能把所有的哈希值都进行映射到服务端ip上,所以这里需要用到哈希环。如下图:

●哈希值如果需要ip1和ip2之间的,则应该选择ip2作为结果;
●哈希值如果需要ip2和ip3之间的,则应该选择ip3作为结果;
●哈希值如果需要ip3和ip4之间的,则应该选择ip4作为结果;
●哈希值如果需要ip4和ip1之间的,则应该选择ip1作为结果;

上面这情况是比较均匀情况,如果出现ip4服务器不存在,那就是这样了:

会发现,ip3和ip1直接的范围是比较大的,会有更多的请求落在ip1上,这是不“公平的”,解决这个问题需要加入虚拟节点,比如: 

其中ip2-1, ip3-1就是虚拟结点,并不能处理节点,而是等同于对应的ip2和ip3服务器。 实际上,这只是处理这种不均衡性的一种思路,实际上就算哈希环本身是均衡的,你也可以增加更多的虚拟节点来使这个环更加平滑,比如: 

 这个彩环也是“公平的”,并且只有ip1,2,3,4是实际的服务器ip,其他的都是虚拟ip。 那么我们怎么来实现呢? 对于我们的服务端ip地址,我们肯定知道总共有多少个,需要多少个虚拟节点也有我们自己控制,虚拟节点越多则流量越均衡,另外哈希算法也是很关键的,哈希算法越散列流量也将越均衡。 实现:

package com.example.demo.balance;

import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 一致性哈希算法
 *
 * @author liwenchao
 */
public class ConsistentHashLoadBalance {

    private static final SortedMap<Integer, String> INTEGER_STRING_TREE_MAP = new TreeMap<>();

    /**
     * 虚拟节点个数
     */
    private static final int VIRTUAL_NODES = 160;

    static {
        //对每个真实节点添加虚拟节点,虚拟节点会根据哈希算法进行散列
        for (String ip : ServerIps.LIST) {
            for (int i = 0; i < VIRTUAL_NODES; i++) {
                int hash = getHash(ip + "VN" + i);
                INTEGER_STRING_TREE_MAP.put(hash, ip);
            }
        }
    }

    private static String getServer(String client) {
        int hash = getHash(client);
        //得到大于该Hash值的排好序的Map
        SortedMap<Integer, String> subMap = INTEGER_STRING_TREE_MAP.tailMap(hash);
        //大于该hash值的第一个元素的位置
        Integer nodeIndex = subMap.firstKey();
        //如果不存在大于该hash值的元素,则返回根节点
        if (nodeIndex == null) {
            nodeIndex = INTEGER_STRING_TREE_MAP.firstKey();
        }
        // 返回对应的虚拟节点名称
        return subMap.get(nodeIndex);
    }

    private static int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash ^ str.charAt(i)) * p;
        }
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        // 如果算出来的值为负数则取其绝对值
        if (hash < 0) {
            hash = Math.abs(hash);
        }
        return hash;
    }

    public static void main(String[] args) {
        // 连续调用10次,随机10个client
        for (int i = 0; i < 10; i++) {
            System.out.println(getServer("client" + i));
        }
    }


}

执行结果

192.168.0.9
192.168.0.9
192.168.0.6
192.168.0.5
192.168.0.10
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.5
192.168.0.8

7,最小活跃数算法-LeastActiveLoadBalance

前面几种方法主要目标是使服务端分配到的调用次数尽量均衡,但是实际情况是这样吗?调用次数相同,服务器的负载就均衡吗?当然不是,这里还要考虑每次调用的时间,而最小活跃数算法则是解决这种问题的。
活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求。此时应优先将请求分配给该服务提供者。在具体实现中,每个服务提供者对应一个活跃数。初始情况下,所有服务提供者活跃数均为0。每收到一个请求,活跃数加1,完成请求后则将活跃数减1。在服务运行一段时间后,性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求、这就是最小活跃数负载均衡算法的基本思想。除了最小活跃数,最小活跃数算法在实现上还引入了权重值。所以准确的来说,最小活跃数算法是基于加权最小活跃数算法实现的。举个例子说明一下,在一个服务提供者集群中,有两个性能优异的服务提供者。某一时刻它们的活跃数相同,则会根据它们的权重去分配请求,权重越大,获取到新请求的概率就越大。如果两个服务提供者权重相同,此时随机选择一个即可。
实现:
因为活跃数是需要服务器请求处理相关逻辑配合的,一次调用开始时活跃数+1,结束是活跃数-1,所以这里就不对这部分逻辑进行模拟了,直接使用一个map来进行模拟。

package com.example.demo.balance;

import java.util.*;

/**
 * 最小活跃数算法
 *
 * @author liwenchao
 */
public class LeastActiveLoadBalance {

    private static String getServer() {

        // 找出当前活跃数最小的服务器
        Optional<Integer> minValue = ServerIps.ACTIVITY_LIST.values().stream().min(Comparator.naturalOrder());
        if (minValue.isPresent()) {
            List<String> minActivityIps = new ArrayList<>();
            ServerIps.ACTIVITY_LIST.forEach((ip, activity) -> {
                if (activity.equals(minValue.get())) {
                    minActivityIps.add(ip);
                }
            });
            // 最小活跃数的ip有多个,则根据权重来选,权重大的优先
            if (minActivityIps.size() > 1) {
                // 过滤出对应的ip和权重
                Map<String, Integer> weightList = new LinkedHashMap<String, Integer>();
                ServerIps.WEIGHT_LIST.forEach((ip, weight) -> {
                    if (minActivityIps.contains(ip)) {
                        weightList.put(ip, ServerIps.WEIGHT_LIST.get(ip));
                    }
                });
                int totalWeight = 0;
                // 如果所有权重都相等,那么随机一个ip就好了
                boolean sameWeight = true;
                Object[] weights = weightList.values().toArray();
                for (int i = 0; i < weights.length; i++) {
                    Integer weight = (Integer) weights[i];
                    totalWeight += weight;
                    if (sameWeight && i > 0 && !weight.equals(weights[i - 1])) {
                        sameWeight = false;
                    }
                }
                Random random = new Random();
                int randomPos = random.nextInt(totalWeight);
                if (!sameWeight) {
                    for (String ip : weightList.keySet()) {
                        Integer value = weightList.get(ip);
                        if (randomPos < value) {
                            return ip;
                        }
                        randomPos = randomPos - value;
                    }
                }
                return (String) weightList.keySet().toArray()[new Random().nextInt(weightList.size())];
            } else {
                return minActivityIps.get(0);
            }
        } else {
            return (String) ServerIps.WEIGHT_LIST.keySet().toArray()[new Random().nextInt(ServerIps.WEIGHT_LIST.size())];
        }
    }

    public static void main(String[] args) {
        // 连续调用10次,随机10个client
        for (int i = 0; i < 10; i++) {
            System.out.println(getServer());
        }
    }

}

这里因为不会对活跃数进行操作,所以结果是固定的(担任在随机权重的时候会随机)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/509485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聊聊那些年我们实现java AOP几种常见套路

前言 有一定开发经验的同学对AOP应该很了解吧&#xff0c;如果不了解&#xff0c;可以先查看如下文章进行科普一下https://baike.baidu.com/item/AOP/1332219?fraladdin&#xff0c;再来阅读本文。 示例前置准备 注&#xff1a; 本示例基于springboot进行演示 1、在项目pom…

将ABC文件 通过BlendShape导出为FBX>

将ABC文件 通过BlendShape导出为FBX 一、应用场景&#xff1a; 此项目为高中化学实验案例&#xff0c;为实现保鲜膜 模拟动画&#xff0c;这里通过使用MarvelousDesigner来结算出动画效果&#xff0c;导出ABC格式带动画后&#xff0c;导入到maya当中&#xff0c;这里因为需要…

SSM框架学习-注解开发定义bean

注解开发定义的bean和xml文件定义的bean有以下区别&#xff1a; 配置方式不同&#xff1a;注解方式是直接在Java类中使用注解来定义bean&#xff0c;而XML方式则是在XML文件中配置bean。 配置信息不同&#xff1a;注解方式在注解内配置bean的属性&#xff0c;如Value&#xff…

springboot整合ES

也可以直接看到最后&#xff0c;直接看到最后&#xff0c;中间都是废话废话废话&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;好气啊 1.刚下载完成,输入localhost:9200就报错&#xff0c;整个人都不太好了 [2023-05-10T14:35:59,002][WARN ][o.…

DC域控服务器与辅助DC域控服务器创建

DC域控服务器与辅助DC域控服务器创建 一、准备条件 在虚拟机上准备三台Windows Server 2008 R2 ,一台作为主域控&#xff0c;一台作为额外域控辅域控&#xff0c;一台作为客户端。 主域控 的IP地址为--192.168.1.190, 注意&#xff1a;(Windows Server 2003 需要 设置 DNS为127…

烽火HG680KA-Hi3798MV310-当贝纯净桌面-卡刷固件包

烽火HG680KA-Hi3798MV310-当贝纯净桌面-卡刷固件包-内有教程 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&#xff1b; 4、大量精简内置的没用的软件&#xff…

pytorch搭建EfficientnetV2网络

文章目录 前言一、EfficientnetV2二、网络结构1.Fused_MBConv2.MBConv 三、整体代码总结 论文地址&#xff1a;https://arxiv.org/abs/2104.00298 官方代码&#xff1a;https://github.com/google/automl/tree/master/efficientnetv2 参考链接&#xff1a;https://blog.csdn.ne…

经典:DotNetBar Suite UI 7.9 for WPF Crack

创建专业的 WPF 应用程序 DotNetBar Suite for WPF 是超过 38 个本机 Windows Presentation Foundation 控件的工具箱&#xff0c;用于创建专业的 WPF 应用程序。 Office 2016 类样式添加到功能区、日程安排和其他控件... 我们痴迷于控制性能和像素级细节。我们很自豪地说&…

2023年杭州助理工程师职称申报评审流程是什么呢?社保单位不一致怎么办?

助理工程师证&#xff0c;又称为初级工程证或者初级职称。助理工程师&#xff0c;是指初级工程技术人员的职务名称。有了助理工程师证你可以评中级工程师证&#xff0c;也可以应聘、在职、上岗、加薪、企业升资质和招投标都用的到。助理工程师证是评审获得的&#xff0c;评审报…

如何正确使用 Facebook 反链,增强网站在搜索引擎中的曝光度

在当今数字化时代&#xff0c;拥有一个强大的在线存在感是企业成功的关键之一。而在建立有效的在线存在感时&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;扮演着重要的角色。而其中一个重要的SEO策略是利用反链来增强网站在搜索引擎中的曝光度。 然而&#xff0c;许多…

【服务器数据恢复】HP双循环Raid5磁盘阵列数据恢复案例

服务器数据恢复环境&#xff1a; 一台HP DL系列服务器&#xff0c;通过hp smart array控制器挂载一台磁盘阵列设备&#xff0c;作为公司内部的文件服务器使用&#xff1b; 该磁盘阵列设备中有一组由十几块SCSI硬盘组建的RAID5&#xff1b; 上层安装LINUX操作系统并部署了NFSFTP…

结算更高效,成本更节省,风控更全面,用友银企联助力万家企业加速数字变革

数字经济蓬勃发展的当下&#xff0c;在业绩增长和管理提效的双重压力下&#xff0c;企业纷纷投身于数字化、智能化转型升级&#xff0c;通过大数据及新一代人工智能技术寻求产业变革&#xff0c;以实现企业业务创新与管控升级。银企联作为企业与银行信息交互的通道&#xff0c;…

SpringBoot——pom文件:parent

先看一看&#xff1a; 本次我们主要介绍SpringBoot的文件&#xff0c;先来看一看里面都有什么内容&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <!--XML文件的抬头--> <!--一些约束以及明明空间信息--> <project xmlns&qu…

知识图谱实现全域数据资产智能管理与运营

案例名称 基于知识图谱的全域数据资产智能管理与运营 案例简介 该方案通过数据资产元数据构建引擎、列算子血缘引擎、关系挖掘引擎和数据资产目录挂载引擎的部署&#xff0c;可快速实现金融机构数据资产的业务目录分类以及数据资产标签集合建设。通过可视化引擎管…

Ubuntu配置Samba服务

Ubuntu配置Samba服务 一、安装samba二、配置samba服务器三、win系统配置四、检查你的虚拟机五、注意 一、安装samba 前提&#xff1a;已经换好源&#xff0c;不然下载很慢或者不成功 未换执行以下命令 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo vim/etc…

虹科案例 | 使用PRP协议解决广播行业中实现高可用性和亚微秒同步难题

案例背景 BROADCASTING PUBLIC ENTITY主要为用户提供电视频道和广播频道&#xff0c;为了带来更好的视听体验&#xff0c;该公司必须更新其无线电前端系统的基础设施。前端的主要功能是接收来自广播电台的现场音频并将其编码为压缩格式&#xff0c;例如AAC&#xff0c;然后将多…

unity 完全复刻flappy bird

文章目录 一、 介绍制作bird向右移动的效果基本动画转场渐隐效果dotween 平滑摇头效果柱子控制器碰撞检测下载项目文件 一、 介绍 Flappy Bird是一款由越南开发者Dong Nguyen于2013年发布的2D跳跃游戏。玩家需要控制一只小鸟躲避障碍物&#xff0c;通过不断飞行获得分数。游戏…

如果把ChatGPT和“挖呀挖”的黄老师结合起来,她可以为你做什么事情?

ChatGPT曾经2个月用户过亿的事情已成为过去&#xff0c;虽然我也成为了其中的一份子&#xff0c;感受着他的无所不能&#xff0c;但从中也的确发现了他的一些不能做的事情。而近期爆火的“挖呀挖”的黄老师&#xff0c;几天粉丝疯涨几百万&#xff0c;也的确值得我们思考。 那么…

kafka安装及环境搭建

1. 下载 下载地址&#xff1a;Apache Kafka 我这里下载的是 3.2.1 版本。 2. 上传并解压 上传到 linux 下的 /home/software/ 目录下&#xff0c;然后解压 kafka_2.13-3.2.1.tgz 包到/usr/local/ cd /home/software tar -zxvf kafka_2.13-3.2.1.tgz -C /usr/local # -C 选…

odoo的一些基础概念

概述 三层体系结构&#xff0c;表示层是HTML5、JavaScript和CSS的组合&#xff0c;逻辑层专门用Python编写&#xff0c;而数据层只支持PostgreSQL作为RDBMS。 服务器和客户端扩展都打包为模块&#xff0c;可选地加载到数据库中。模块是针对单一目的的函数和数据的集合。Odoo中…