zoukankan      html  css  js  c++  java
  • 负载均衡算法示例

    声明:本文根据鲁班学院周瑜老师课程笔记整理而来

    负载均衡的介绍?

      负载均衡,英文名称Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。
      通过某种负载分担技术,将外部发送来的请求均匀分布到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。
      负载均衡能够平均分配客户请求到服务器阵列,借此提供快速获取重要数据,解决大量并发访问服务器问题,这种集群技术可以用最少的投资获得接近于大型主机的性能。
    负载均衡方式?
      负载均衡分为软件负载均衡和硬件负载均衡。
    软件负载均衡:
      常见的负载均衡软件有Nginx,LVS,HAProxy。
      (总结)Nginx/LVS/HAProxy负载均衡软件的优缺点:http://www.ha97.com/5646.html
      三大主流软件负载均衡器对比(LVS,Nginx,HAProxy):http://www.21yunwei.com/archives/5824
    硬件负载均衡:
      常见的负载均衡硬件有Array,F5.
    负载均衡算法?
      常见的负载均衡算法有:随机算法,加权轮询算法,一致性hash算法,最小活跃数算法。

    算法的前提条件:

      定义一个服务器列表,每个负载均衡的算法会从中挑选一个服务器作为算法的结果:

    /**
     * 定义一个服务器列表,每个负载均衡算法会从中挑选一个服务器作为算法结果
     * @author Administrator
     *
     */
    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");
    }

    随机算法--RandomLoadBalance

      首先来个最简单的随机算法的实现。

    /**
     * 随机算法
     * @author Administrator
     *
     */
    public class JavaRandom {
        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());
            }
        }
    }

      运行结果:

      

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

      但是,上面的随机算法适用于每台机器的性能差不多的时候,实际上,上产中可能某些机器的性能更高一点,它可以处理更多的请求,所以我们可以对每台机器设置一个权重。

      我们在ServerIps类中增加服务器权重对应关系的Map,设置权重之和为50。

        //增加权重
        public static final Map<String,Integer> WEIGHT_LIST=new HashMap<>();
        static{
            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);
        }

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

    权重随机算法:

      简单的思路是,把每个服务器按它对应的服务器进行复制。

    /**
     * 增加权重的随机算法
     * @author Administrator
     *
     */
    public class JavaWeightRandom {
        public static String getServer(){
            //1.首先根据权重进行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);
                }
            }
            //2.在list数组中使用随机算法进行取值
            //生成一个随机数作为list的下标值
            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());
            }
        }
    }

      运行结果:

      

      这种实现方法在遇到权重之和特别大的时候,就会比较消耗内存,因为需要对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;

      1.offset<5 is false,所以不在[0,5)区间,将offset = offset-5(offset=2)

      2.offset<3 is true,所以处在[5,8)区间,所以应该选择服务器B

    /**
     * 将权重模拟在一维坐标轴上
     * @author Administrator
     *
     */
    public class JavaWeightRandom2 {
        public static String getServer(){
            //定义总权重属性
            int totalWeight = 0;
            boolean sameWeight = true;//如果所有权重都相等,那么就随机一个IP
            //得到所有的权重,生成一维坐标轴
            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;
                }
            }
            
            //生成一个随机数作为list的下标值
            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());
            }
        }
    }

      测试结果:

      

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

    轮询算法--RoundRobinLoadBalance

      简单的轮询算法很简单

      

    /**
     * 简单的轮询算法
     * @author Administrator
     *
     */
    public class JavaRoundRobin {
        //当前循环的位置
        private static Integer pos = 0;
        public static String getServer(){
            String ip = null;
            //pos同步
            synchronized (pos) {
                if(pos >= ServerIps.LIST.size()){
                    pos = 0;
                }
                ip = ServerIps.LIST.get(pos);
                pos++;
            }
            return ip;
        }
        public static void main(String[] args) {
            for(int i=0;i<10;i++){
                System.out.println(getServer());
            }
        }
    }

      测试结果:

      

       这种算法很简单也很公平,每台服务器轮流来进行服务,但是,有的机器性能好,所以应当能者多劳,和随机算法一样,加上权重这个维度之后,其中一种实现方法就是复制发,这种复制算法和随机算法一样,缺点都是比较消耗内存,那么有没有用其他实现方法?我们下面来介绍一种算法。

      

  • 相关阅读:
    PHP原生实现,校验微信公众号||小程序服务器地址
    TP3.2校验微信公众号||小程序 服务器地址
    【微信小程序】解决 竖向<scroll-view>组件 “竖向滚动页面出现遮挡”问题
    【微信小程序】:confirm(删除提示)
    【微信小程序】:评论、回复和删除功能 -- 2017/7/14
    微信小程序:bindtap方法传参
    TP3.2之WHERE组合条件处理
    Python:导入numpy报错 No module named numpy
    Python: 二进制、八进制、十六进制转换或者输出
    Python:数字的格式化输出
  • 原文地址:https://www.cnblogs.com/wk-missQ1/p/13341377.html
Copyright © 2011-2022 走看看