四种负载均衡算法思想

四种负载均衡算法思想

  • 随机法
  • 轮询
  • 一致hash法
  • 最小活跃数

-------------随机

​ 若只是单纯的使用Random进行随机的话,可以实现,但是如果服务器的负载能力大小不一样,

就会造成配置高的服务器处于空闲或者负载量小,而配置低的服务器任务繁重。因此为每台服务器

设置一个权重来表明负载的能力大小。这是如何选取就有两个方式,一个是根据权重大小,向服务

List集合中添加多少个,这样做的缺点就在于当服务器过多,或者权重值过大,那这个list集合就

会很大,并且每更改一次就要重新维护一次,不适合动态。这是可以采用命中机制

》假如现在有一个Map<ip,weight>,里面的weight集合为【10,5,10】

》这时的请求数量为6

》6<10~~~~~~~~~~~>返回当前权重为10的ip

》若请求数为11;

》11>10,进行相减得1,再判断1<5命中,返回权重为5的ip地址

实现代码如下:


public class Randomsolution {

    public static String getserver() {
       /*//在服务器的负载能力差不多的情况下合适,可一但服务器的性能此时差别比较大,就会造成性能强的服务器处于空闲或者低载,请求的分配就不均衡
        Random r = new Random();
        return ServerIps.iplist.get(r.nextInt(ServerIps.iplist.size()));*/
        /*为每一台服务器设置权重,然后按权重向list集合中增加几个,在执行上述的随机算法,但是如果权重过大,就会形成一个很大的list,一定会影响速度,并且也过于。。。*/
        /*根据当前的请求数来判断,即如果权重数组为【2,5,3】,在进行命中处理,假如为3<2,则进行3-2处理后;1<5则返回权重为5的ip
         * 如果权重一样的话,直接采用随机*/
        int totalWeight = 0;
        for (Integer weight : ServerIps.WEIGHT_IPMAP.values()) {
            totalWeight += weight;
        }

        int requestsize = new Random().nextInt(totalWeight);
        System.out.println(requestsize);

        for (String ip : ServerIps.WEIGHT_IPMAP.keySet()) {
            int weight = ServerIps.WEIGHT_IPMAP.get(ip);
            if (requestsize < weight) {
               return ip;
            }
            requestsize = requestsize - weight;
        }
        return null;
    }

---------------------轮询

轮询就是按照当前的请求id经过取模和命中机制返回服务器的ip,具体的实现如下:

》若请求的id为5;此时服务器的权重列表为【5,3,1】;

》计算出服务器的权重的总和为9

》5%9=5(这一步是为了保证id过大的时候,始终能够命中)

》和上面的随机的命中算法是一样的

》如果id从0开始,则最终的结果会是A服务器五次,B服务器三次,C服务器一次,按照此规律进行循环

实现代码如下:

public class RoundRobin {
    public static String getIp(){
        int totalWeight = 0;
        for(Integer weight : ServerIps.WEIGHT_IPMAP.values()) {
            totalWeight += weight;
        }
        int requestid = requestId.getrequestId();
        int iid=requestid % totalWeight;
        System.out.println(requestid);
        for (String ip : ServerIps.WEIGHT_IPMAP.keySet()) {
            int weight = ServerIps.WEIGHT_IPMAP.get(ip);
            if (iid < weight) {
                return ip;
            }
            iid = iid - weight;
        }
        return null;
    }

    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            System.out.println(getIp());
        }
    }

这只是简单的轮询,如果能够让这些请求交叉分布就更好了,平滑加权轮询的出现就是为了解决这个问题,这也是Nginx的负载均衡机制(简单思想)

》采用Map<ip,weight<ip,current’weight>>的数据结构,weight对象用来记载当前ip的实时权重值

》若初始的权重为【5,3,1】,每次循环初始化到weight对象中并封装到map集合中(即当前的currentweight+初始的权重值,作为当前的权重值)

》找出当前weight对象中maxCurrentweight,即当前权重最大的点

》进行减操作maxCurrentweight-totalweight,将结果赋给currentWeight,返回当前权重值的ip;

具体代码如下:

public class SmoothRoundRobin {
    /*平滑加权轮询算法*/
    public static HashMap<String,Weight> weightMap = new LinkedHashMap<>();
    public static int totalweight =0;

    /*计算weight的总和*/
    public static  Integer  gettotalweight(){
        for(Integer weight:ServerIps.WEIGHT_IPMAP.values()){
            totalweight +=weight;
        }
        return totalweight;
    }

    public static void InitweightMap(){
        for(String ip:ServerIps.WEIGHT_IPMAP.keySet()){
            Integer weight = ServerIps.WEIGHT_IPMAP.get(ip);
            weightMap.put(ip,new Weight(ip,weight,0));
        }
        gettotalweight();
    }

    public static  String getServer(){
        if(weightMap.isEmpty()){
            InitweightMap();
        }

        /*为currentweight赋值,每次的重新计算当前权重*/
        for(Weight w:weightMap.values()){
            w.setCurrentweight(w.getCurrentweight()+w.getWeight());
        }
        System.out.println(weightMap);
        /*找出weightMap中最大的currentweight*/
        Weight maxCurrentweight = null;

        for(Weight weight:weightMap.values()){
            if(maxCurrentweight==null||weight.getCurrentweight()>maxCurrentweight.getCurrentweight()){
                maxCurrentweight=weight;
            }
        }
        /*对maxweight进行-sumweight处理*/
        maxCurrentweight.setCurrentweight(maxCurrentweight.getCurrentweight()-totalweight);
        return maxCurrentweight.getIp();
    }

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

}

这样就会使输出结果更加均衡。

------------------------一致hash法

又称为hash环法,根据请求者的IP计算出其hashcode,去查询由服务器ip的hashcode所构成的一个环,这个环上面有很多虚节点,虚节点的多少可以有权重而定,

找出比当前iphash值大的第一个点作为返回。

注意:一定要保证hash环是一个有序的环(采用TreeMap实现)

具体代码如下:


public class ConsistenHash {

    public static TreeMap<Integer,String> hashcirle=new TreeMap();
    private static final int childrensize = 20;

    //初始化hash环
    static {
        for (String ip:ServerIps.iplist){
            for(int i=0;i<childrensize;i++){
                int nodehash = geHash(ip+i);
                hashcirle.put(nodehash,ip);
            }
        }
        System.out.println(hashcirle);
    }
   /*根据请求的ip的hash值,找到比这个值大的一颗子树(同样有序的),取出子树中的最小节点,返回此节点的ip值,如没有这样一课子树,则返回整棵树最小节点的ip值
   * 问题:若此时的最小节点出了故障,或者负载量太高,再分配给他则会造成等待,或者不成功,应该再加上一个值来反映当前结点的活跃状态,根据活跃状态判断是否可取
   * 依次向下排取,但是这种方法的问题又出来了,可以将活跃节点用一个有序表来进行映射,这时候取对应的点*/
    public static String getServer(String clientip){
        int clientiphash = geHash(clientip);
        SortedMap<Integer, String> integerStringSortedMap = hashcirle.tailMap(clientiphash);
        if(integerStringSortedMap!=null){
            return integerStringSortedMap.get(integerStringSortedMap.firstKey());
        }else {
            return hashcirle.get(hashcirle.firstKey());
        }
    }

    public static  int geHash(String str){
        final int p=115487;
        int hash=(int)857422411L;
        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) {
        for(int i=0;i<10;i++){
            String s = getServer("192.168.1."+i);
            System.out.println(s);
        }

    }
}

-------------------最小活跃数

这个就是动态实现了,需要根据服务器此时的请求多少和其他影响因素得出一个活跃因子,然后根据这个值去判断由哪一个服务器来处理当前请求,可以结合上面的三种方法一起实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值