您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

ribbon的常用负载均衡算法分析

时间:2020-07-23 15:50:04  来源:  作者:

1.Ribbon介绍

因为微服务是目前互联网公司比较流行的架构,所以spring就提供了一个顶级框架-spring cloud,来解决我们在开发微服务架构中遇到的各种各样的问题,今天的主角是spring cloud 框架中集成的组件Ribbon,那么Ribbon能解决什么问题呢,我们来思考下面的问题。

​ 微服务架构中的每个服务为了高可用,很大程度上都会进行集群,我们假设现在集群了3个user服务,同时能提供相同的服务,问题来了,我们如何决定调用这3个user服务中的哪一个呢?

​ 根据不同分析角度,会有不同的答案,也可以理解为根据不同的情况,我们可以写不同的算法,来决定到底此时此刻,调用这3个user服务的哪一个,那么,Ribbon就给我们提供了不同的算法,我们可以根据业务场景,调整配置文件,决定到底使用哪个算法,这样,算法中就会计算出调用哪个user服务了。

2.准备工作

1)我们准备一个eureka注册中心

2)再准备一个order服务

3)再准备3个相同代码的user服务,这样,order服务通过eureka注册中心,就可以发现user的3个服务

3.Ribbon的常用负载均衡策略

Ribbon是通过IRule的这个接口来选择3个user服务中的哪个的,但是实际执行的代码肯定是继承了这个接口的实现类,所以选择不同的实现类,就会选择不同负载均衡策略

public interface IRule {

    Server choose(Object var1);

    void setLoadBalancer(ILoadBalancer var1);

    ILoadBalancer getLoadBalancer();
}

3.1. RoundRobinRule 轮询策略

此策略是Ribbon的默认策略,是按照顺序,依次对所有的user服务进行访问。

通过重写IRule的choose方法,来选择并返回决定调用的user服务,在下面的源码中,List allServers = lb.getAllServers(); 获得了所有的3个user服务实例,int nextServerIndex = this.incrementAndGetModulo(serverCount); 保存了当前调用的user实例的序号,然后就可以按照顺序调用下一个user服务了

public Server choose(ILoadBalancer lb, Object key) {
    if (lb == null) {
        log.warn("no load balancer");
        return null;
    } else {
        Server server = null;
        int count = 0;

        while(true) {
            if (server == null && count++ < 10) {
                List<Server> reachableServers = lb.getReachableServers();
                List<Server> allServers = lb.getAllServers();
                int upCount = reachableServers.size();
                //总服务实例数量
                int serverCount = allServers.size();
                if (upCount != 0 && serverCount != 0) {
                    int nextServerIndex = this.incrementAndGetModulo(serverCount);
                    server = (Server)allServers.get(nextServerIndex);
                    if (server == null) {
                        Thread.yield();
                    } else {
                        if (server.isAlive() && server.isReadyToServe()) {
                            return server;
                        }

                        server = null;
                    }
                    continue;
                }

                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            if (count >= 10) {
                log.warn("No available alive servers after 10 tries from load balancer: " + lb);
            }

            return server;
        }
    }
}

debug的图例:

ribbon的常用负载均衡算法分析

 

3.2. RoundRobinRule 随机策略

就和这个策略的名字一样,是对user的3个服务的随机调用,所以不存在规律,如下源码中int index = this.chooseRandomInt(serverCount); 通过随机数来选择下标,所以对user服务的调用是随机的

public Server choose(ILoadBalancer lb, Object key) {
    if (lb == null) {
        return null;
    } else {
        Server server = null;

        while(server == null) {
            if (Thread.interrupted()) {
                return null;
            }

            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();
            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

            int index = this.chooseRandomInt(serverCount);
            server = (Server)upList.get(index);
            if (server == null) {
                Thread.yield();
            } else {
                if (server.isAlive()) {
                    return server;
                }

                server = null;
                Thread.yield();
            }
        }

        return server;
    }
}

debug的图例:

ribbon的常用负载均衡算法分析

 

3.3. WeightedResponseTimeRule响应时间加权重策略

根据user的3个服务的响应时间来分配权重,响应时间越长的服务,权重越低,那么被调用的概率也就越低。相反,响应时间越短的服务,权重越高,被调用的概率也就越高

响应时间加权重策略的实现分为两步:

  1. WeightedResponseTimeRule实现类中默认情况下每隔30秒会统计一次每个服务的权重,在此30秒内,用的是轮询策略
  2. 30秒之后,会根据统计的结果来分配每个实例的权重,然后根据权重来分配调用次数
extends RoundRobinRulepublic Server choose(ILoadBalancer lb, Object key) {
    if (lb == null) {
        return null;
    } else {
        Server server = null;

        while(server == null) {
            List<Double> currentWeights = this.accumulatedWeights;
            if (Thread.interrupted()) {
                return null;
            }

            List<Server> allList = lb.getAllServers();
            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

            int serverIndex = 0;
            double maxTotalWeight = currentWeights.size() == 0 ? 0.0D : (Double)currentWeights.get(currentWeights.size() - 1);
            //在30秒之内,maxTotalWeight变量会一直是0.0
            if (maxTotalWeight >= 0.001D && serverCount == currentWeights.size()) {
                double randomWeight = this.random.nextDouble() * maxTotalWeight;
                int n = 0;

                for(Iterator var13 = currentWeights.iterator(); var13.hasNext(); ++n) {
                    Double d = (Double)var13.next();
                    if (d >= randomWeight) {
                        serverIndex = n;
                        break;
                    }
                }

                server = (Server)allList.get(serverIndex);
            } else {
                server = super.choose(this.getLoadBalancer(), key);
                if (server == null) {
                    return server;
                }
            }

            if (server == null) {
                Thread.yield();
            } else {
                if (server.isAlive()) {
                    return server;
                }

                server = null;
            }
        }

        return server;
    }
}

debug的图例:

ribbon的常用负载均衡算法分析

 

3.4. RetryRule 重试策略

重试策略是指通过轮询策略选出一个实例,然后去访问,如果此实例为null或者已经失效,那么会重试其他的实例,answer = this.subRule.choose(key); 会根据轮询策略选择一个实例,然后if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline)判断如果实例为null或者失效,那么会重新选择

public Server choose(ILoadBalancer lb, Object key) {
    long requestTime = System.currentTimeMillis();
    long deadline = requestTime + this.maxRetryMillis;
    Server answer = null;
    answer = this.subRule.choose(key);
    if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline) {
        InterruptTask task = new InterruptTask(deadline - System.currentTimeMillis());

        while(!Thread.interrupted()) {
            answer = this.subRule.choose(key);
            if (answer != null && answer.isAlive() || System.currentTimeMillis() >= deadline) {
                break;
            }

            Thread.yield();
        }

        task.cancel();
    }

    return answer != null && answer.isAlive() ? answer : null;
}
ribbon的常用负载均衡算法分析

 

3.5. BestAvailableRule 最低并发策略

会根据每个服务实例的并发数量来决定,访问并发数最少的那个服务,int concurrentConnections = serverStats.getActiveRequestsCount(currentTime); 会获得当前遍历的实例的并发数,然后和其他的实例的并发数进行判断,最终访问并发量最少的那个实例

public Server choose(Object key) {
    if (this.loadBalancerStats == null) {
        return super.choose(key);
    } else {
        List<Server> serverList = this.getLoadBalancer().getAllServers();
        int minimalConcurrentConnections = 2147483647;
        long currentTime = System.currentTimeMillis();
        Server chosen = null;
        Iterator var7 = serverList.iterator();

        while(var7.hasNext()) { //遍历所有的实例
            Server server = (Server)var7.next();
            ServerStats serverStats = this.loadBalancerStats.getSingleServerStat(server);
            if (!serverStats.isCircuitBreakerTripped(currentTime)) {
                int concurrentConnections = serverStats.getActiveRequestsCount(currentTime); //判断并发数,并和已经判断出的最少的并发数比较
                if (concurrentConnections < minimalConcurrentConnections) {
                    minimalConcurrentConnections = concurrentConnections;
                    chosen = server;
                }
            }
        }

        if (chosen == null) {
            return super.choose(key);
        } else {
            return chosen;
        }
    }
}

3.6. AvailabilityFilteringRule 可用过滤策略

此策略会聪明的过滤掉一直失败并被标记为circuit tripped的user服务,而且会过滤掉那些高并发的user服务

public Server choose(Object key) {
    int count = 0;

    for(Server server = this.roundRobinRule.choose(key); count++ <= 10; server = this.roundRobinRule.choose(key)) {
        //通过predicate来过滤
        if (this.predicate.Apply(new PredicateKey(server))) {
            return server;
        }
    }
    //过滤掉一些服务之后,会采用轮询的方式调用剩下的服务
    return super.choose(key);
}

3.7. ClientConfigEnabledRoundRobinRule 自定义策略

此策略本身并没有实现什么特殊的处理逻辑,但是可以通过重置LoadBalancer来达到自定义一些高级策略的目的,可以重写initWithNiwsConfig和setLoadBalancer

public void initWithNiwsConfig(IClientConfig clientConfig) {
    this.roundRobinRule = new RoundRobinRule();
}

public void setLoadBalancer(ILoadBalancer lb) {
    super.setLoadBalancer(lb);
    this.roundRobinRule.setLoadBalancer(lb);
}

public Server choose(Object key) {
    if (this.roundRobinRule != null) {
        return this.roundRobinRule.choose(key);
    } else {
        throw new IllegalArgumentException("This class has not been initialized with the RoundRobinRule class");
    }
}


Tags:Ribbon   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
网关组件 Zuul 性能一般,未来将退出 Spring Cloud 生态圈,所以直接使用 GateWay,把 GateWay 划分到第一代 Spring Cloud 核心组件中。各组件整体结构如下:Gateway:所有服务的入口...【详细内容】
2021-03-03  Tags: Ribbon  点击:(213)  评论:(0)  加入收藏
大家好,我是阿七。在上一篇文章中,我们已经实现了内容中心总能够调用用户中心,那如何实现负载均衡呢?请听阿七为你娓娓道来。(没看到上篇文章的同学请戳这里:实战(一)nacos注册与发...【详细内容】
2020-08-26  Tags: Ribbon  点击:(87)  评论:(0)  加入收藏
1.Ribbon介绍因为微服务是目前互联网公司比较流行的架构,所以spring就提供了一个顶级框架-spring cloud,来解决我们在开发微服务架构中遇到的各种各样的问题,今天的主角是sprin...【详细内容】
2020-07-23  Tags: Ribbon  点击:(97)  评论:(0)  加入收藏
在学习Ribbon之前,先看一下这张图,这张图完美的把Ribbon的基础架构给描述出来了这张图的核心是负载均衡管理器,围绕着它的是外面的这5大功能点,咱们就从核心开始看然后再带出来...【详细内容】
2019-11-12  Tags: Ribbon  点击:(118)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(9)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(19)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(13)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(37)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
相关文章
最新更新
栏目热门
栏目头条