Java代码实现负载均衡六种算法(强烈建议收藏)

1、引言

负载均衡是我们平时常见的解决高并发问题的一大法宝,负载均衡从字面理解就是将请求均衡分发到后台的服务器,本文通过例子模拟几种常见负载均衡算法的实现。
源码参考:com.leo.demo.loadbalancetes
git地址:https://gitee.com/leo825/sortalgorithm-demos.git

2、负载均衡算法

本文主要介绍一下几种负载均衡算法的实现:

  1. 随机算法
  2. 加权随机算法
  3. 轮询算法
  4. 加权轮询算法
  5. IP-Hash算法
  6. 最小连接数算法
2.1、随机算法(Random)

通过系统随机函数,根据后台服务器的server的地址随机选取其中一台服务器进行访问,根据概率论的相关知识,随着调用量的增加,最终的访问趋于平均,就是达到了均衡的目的。

/**
 * @author Administrator
 * @Date 2019/8/20 15:08
 *
 * 随机法:
 * 负载均衡方法随机的把负载分配到各个可用的服务器上,通过随机数生成算法选取一个服务器。毕竟随机,,有效性受到了质疑
 *
 */
public class TestRandom {
    //    1.定义map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",2);
        ipMap.put("192.168.13.3",4);
    }
    public String Random() {
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);

        Set<String> ipSet=ipServerMap.keySet();

        //定义一个list放所有server
        ArrayList<String> ipArrayList=new ArrayList<String>();
        ipArrayList.addAll(ipSet);

        //循环随机数
        Random random=new Random();
        //随机数在list数量中取(1-list.size)
        int pos=random.nextInt(ipArrayList.size());
        String serverNameReturn= ipArrayList.get(pos);
        return  serverNameReturn;
    }

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

2.2、加权随机算法(WeightRandom)

加权随机算法就是在上面的随机算法的基础上做的优化,比如一些性能好的Server多承担一些,请求根据权重分发到各个服务器。

/**
 * @author Administrator
 * @Date 2019/8/20 15:11
 * 加权随机法:
 * 获取带有权重的随机数字,随机这种东西,不能看绝对,只能看相对。
 */
public class TestWeightRandom {

    //    1.定义map, key-ip,value-weight
    static Map<String, Integer> ipMap = new HashMap<>();

    static {
        ipMap.put("192.168.13.1", 1);
        ipMap.put("192.168.13.2", 2);
        ipMap.put("192.168.13.3", 4);


    }

    public String weightRandom() {
        Map<String, Integer> ipServerMap = new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);

        Set<String> ipSet = ipServerMap.keySet();
        Iterator<String> ipIterator = ipSet.iterator();

        //定义一个list放所有server
        ArrayList<String> ipArrayList = new ArrayList<String>();

        //循环set,根据set中的可以去得知map中的value,给list中添加对应数字的server数量
        while (ipIterator.hasNext()) {
            String serverName = ipIterator.next();
            Integer weight = ipServerMap.get(serverName);
            for (int i = 0; i < weight; i++) {
                ipArrayList.add(serverName);
            }
        }

        //循环随机数
        Random random = new Random();
        //随机数在list数量中取(1-list.size)
        int pos = random.nextInt(ipArrayList.size());
        String serverNameReturn = ipArrayList.get(pos);
        return serverNameReturn;
    }

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


    }
}

2.3、轮询算法(Random)

轮询算法顾名思义,就是按照顺序轮流访问后台服务。

/**
 * @author Administrator
 * @Date 2019/8/20 14:34
 *
 * 轮询法:
 * 轮询算法按顺序把每个新的连接请求分配给下一个服务器,最终把所有请求平分给所有的服务器。
 * 优点:绝对公平
 * 缺点:无法根据服务器性能去分配,无法合理利用服务器资源。
 *
 * @TODO
 */
public class TestRoundRobin {


    //1.定义map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",1);
        ipMap.put("192.168.13.3",1);

    }

    //Integer sum=0;
    Integer  pos = 0;

    public String RoundRobin(){
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);

        //2.取出来key,放到set中
        Set<String> ipset=ipServerMap.keySet();

        //3.set放到list,要循环list取出
        ArrayList<String> iplist=new ArrayList<String>();
        iplist.addAll(ipset);
        String serverName=null;

        //4.定义一个循环的值,如果大于set就从0开始
        synchronized(pos){
            if (pos>=ipset.size()){
                pos=0;
            }
            serverName=iplist.get(pos);
            //轮询+1
            pos ++;
        }
        return serverName;

    }

    public static void main(String[] args) {
        TestRoundRobin testRoundRobin=new TestRoundRobin();
        for (int i=0;i<10;i++){
            String serverIp=testRoundRobin.RoundRobin();
            System.out.println(serverIp);
        }
    }
}
2.4、加权轮询算法(WeightRoundRobin)

加权随机一样,加权轮询,就是在轮询的基础上加上权重,将服务器性能好的,权重高一些。

/**
 * @author Administrator
 * @Date 2019/8/20 15:00
 * 加权轮询法:
 * 该算法中,每个机器接受的连接数量是按权重比例分配的。这是对普通轮询算法的改进,比如你可以设定:
 * 第三台机器的处理能力是第一台机器的两倍,那么负载均衡器会把两倍的连接数量分配给第3台机器。加权轮询分为:简单的轮询、平滑的轮询。
 * 什么是平滑的轮询,就是把每个不同的服务,平均分布。在Nginx源码中,实现了一种叫做平滑的加权轮询(smooth weighted round-robin balancing)
 * 的算法,它生成的序列更加均匀。5个请求现在分散开来,不再是连续的。
 */
public class TestWeightRoundRobin {
    //1.map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",2);
        ipMap.put("192.168.13.3",4);


    }
    Integer pos=0;
    public String weightRoundRobin(){
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);

        Set<String> ipSet=ipServerMap.keySet();
        Iterator<String> ipIterator=ipSet.iterator();

        //定义一个list放所有server
        ArrayList<String> ipArrayList=new ArrayList<String>();

        //循环set,根据set中的可以去得知map中的value,给list中添加对应数字的server数量
        while (ipIterator.hasNext()){
            String serverName=ipIterator.next();
            Integer weight=ipServerMap.get(serverName);
            for (int i = 0;i < weight ;i++){
                ipArrayList.add(serverName);
            }
        }
        String serverName=null;
        if (pos>=ipArrayList.size()){
            pos=0;
        }
        serverName=ipArrayList.get(pos);
        //轮询+1
        pos ++;


        return  serverName;
    }

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


    }
}
2.5、IP-Hash算法(IpHash)

根据hash算法,将请求大致均分的分配到各个服务器上

/**
 * @author Administrator
 * @Date 2019/8/20 15:13
 * IP_Hash算法:
 * hash(object)%N算法,通过一种散列算法把请求分配到不同的服务器上。
 */
public class TestIpHash {
    //    1.定义map, key-ip,value-weight
    static Map<String, Integer> ipMap = new HashMap<>();

    static {
        ipMap.put("192.168.13.1", 1);
        ipMap.put("192.168.13.2", 2);
        ipMap.put("192.168.13.3", 4);
    }

    public String ipHash(String clientIP) {
        Map<String, Integer> ipServerMap = new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);

        //2.取出来key,放到set中
        Set<String> ipset = ipServerMap.keySet();

        //3.set放到list,要循环list取出
        ArrayList<String> iplist = new ArrayList<String>();
        iplist.addAll(ipset);

        //对ip的hashcode值取余数,每次都一样的
        int hashCode = clientIP.hashCode();
        int serverListsize = iplist.size();
        int pos = hashCode % serverListsize;
        return iplist.get(pos);

    }

    public static void main(String[] args) {
        TestIpHash testIpHash = new TestIpHash();
        for(int i = 0; i < 10; i++){
            System.out.println(testIpHash.ipHash("192.168.21.2"));
            System.out.println(testIpHash.ipHash("192.168.21.3"));
        }
    }

}

2.6、最小连接数算法( LeastConnection)

前面我们费尽心思来实现服务消费者请求次数分配的均衡,我们知道这样做是没错的,可以为后端的多台服务器平均分配工作量,最大程度地提高服务器的利用率,但是,实际上,请求次数的均衡并不代表负载的均衡。因此我们需要介绍最小连接数法,最小连接数法比较灵活和智能,由于后台服务器的配置不尽相同,对请求的处理有快有慢,它正是根据后端服务器当前的连接情况,动态的选取其中当前积压连接数最少的一台服务器来处理当前请求,尽可能的提高后台服务器利用率,将负载合理的分流到每一台服务器。

/**
 * @ClassName: TestLeastConnection
 * @Description: 最小连接数算法
 * 最小连接数法是根据服务器当前的连接情况进行负载均衡的,当请求到来时,会选取当前连接数最少的一台服务器来处理请求。
 * @Author: leo825
 * @Date: 2020-02-11 13:02
 * @Version: 1.0
 */
public class TestLeastConnection {
    //1.定义map, key-ip,value-weight
    /**
     * 定义map
     * key:模拟后台服务的ip
     * value:一个Map,map的key是权重,value是接受请求的次数,
     */
    static Map<String, Integer> ipMap = new HashMap<>();
    //模拟请求的次数
    static ThreadLocalRandom random = ThreadLocalRandom.current();

    static {
        ipMap.put("192.168.13.1", random.nextInt(10));
        ipMap.put("192.168.13.2", random.nextInt(10));
        ipMap.put("192.168.13.3", random.nextInt(10));
    }

    //从list中选取接受请求数最少的服务并返回
    public String leastConnection() {
        Iterator<String> ipListIterator = ipMap.keySet().iterator();
        String serverName = null;
        int times = 0;//访问次数
        while (ipListIterator.hasNext()) {
            String tmpServerName = ipListIterator.next();
            int requestTimes = ipMap.get(tmpServerName);
            //第一次需要赋值
            if (times == 0) {
                serverName = tmpServerName;
                times = requestTimes;
            } else {
                //找到最小次数
                if (times > requestTimes) {
                    serverName = tmpServerName;
                    times = requestTimes;
                }
            }
        }
        ipMap.put(serverName, ++times);//访问后+1
        System.out.println("获取到的地址是:" + serverName + ", 访问次数:" + times);
        return serverName;
    }

    public static void main(String[] args) {
        TestLeastConnection testLeastConnection = new TestLeastConnection();
        for (int i = 0; i < 10; i++) {
            testLeastConnection.leastConnection();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leo825...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值