千家信息网

Ribbon的负载均衡策略及原理是什么

发表于:2024-11-24 作者:千家信息网编辑
千家信息网最后更新 2024年11月24日,本篇内容介绍了"Ribbon的负载均衡策略及原理是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
千家信息网最后更新 2024年11月24日Ribbon的负载均衡策略及原理是什么

本篇内容介绍了"Ribbon的负载均衡策略及原理是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

Load Balance负载均衡是用于解决一台机器(一个进程)无法解决所有请求而产生的一种算法。像nginx可以使用负载均衡分配流量,ribbon为客户端提供负载均衡,dubbo服务调用里的负载均衡等等,很多地方都使用到了负载均衡。

使用负载均衡带来的好处很明显:

当集群里的1台或者多台服务器down的时候,剩余的没有down的服务器可以保证服务的继续使用
使用了更多的机器保证了机器的良性使用,不会由于某一高峰时刻导致系统cpu急剧上升
负载均衡有好几种实现策略,常见的有:

随机 (Random)
轮询 (RoundRobin)
一致性哈希 (ConsistentHash)
哈希 (Hash)
加权(Weighted)


ILoadBalance 负载均衡器

ribbon是一个为客户端提供负载均衡功能的服务,它内部提供了一个叫做ILoadBalance的接口代表负载均衡器的操作,比如有添加服务器操作、选择服务器操作、获取所有的服务器列表、获取可用的服务器列表等等。ILoadBalance的继承关系如下:

负载均衡器是从EurekaClient(EurekaClient的实现类为DiscoveryClient)获取服务信息,根据IRule去路由,并且根据IPing判断服务的可用性。

负载均衡器多久一次去获取一次从Eureka Client获取注册信息呢?在BaseLoadBalancer类下,BaseLoadBalancer的构造函数,该构造函数开启了一个PingTask任务setupPingTask();,代码如下:

    public BaseLoadBalancer(String name, IRule rule, LoadBalancerStats stats,            IPing ping, IPingStrategy pingStrategy) {        if (logger.isDebugEnabled()) {            logger.debug("LoadBalancer:  initialized");        }        this.name = name;        this.ping = ping;        this.pingStrategy = pingStrategy;        setRule(rule);        setupPingTask();        lbStats = stats;        init();    }


setupPingTask()的具体代码逻辑,它开启了ShutdownEnabledTimer执行PingTask任务,在默认情况下pingIntervalSeconds为10,即每10秒钟,向EurekaClient发送一次"ping"。

void setupPingTask() {        if (canSkipPing()) {            return;        }        if (lbTimer != null) {            lbTimer.cancel();        }        lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-">


PingTask源码,即new一个Pinger对象,并执行runPinger()方法。

查看Pinger的runPinger()方法,最终根据 pingerStrategy.pingServers(ping, allServers)来获取服务的可用性,如果该返回结果,如之前相同,则不去向EurekaClient获取注册列表,如果不同则通知ServerStatusChangeListener或者changeListeners发生了改变,进行更新或者重新拉取。

完整过程是:

LoadBalancerClient(RibbonLoadBalancerClient是实现类)在初始化的时候(execute方法),会通过ILoadBalance(BaseLoadBalancer是实现类)向Eureka注册中心获取服务注册列表,并且每10s一次向EurekaClient发送"ping",来判断服务的可用性,如果服务的可用性发生了改变或者服务数量和之前的不一致,则从注册中心更新或者重新拉取。LoadBalancerClient有了这些服务注册列表,就可以根据具体的IRule来进行负载均衡。

IRule 路由

IRule接口代表负载均衡策略:

public interface IRule{    public Server choose(Object key);    public void setLoadBalancer(ILoadBalancer lb);    public ILoadBalancer getLoadBalancer();    }


IRule接口的实现类有以下几种:

其中RandomRule表示随机策略、RoundRobinRule表示轮询策略、WeightedResponseTimeRule表示加权策略、BestAvailableRule表示请求数最少策略等等。

随机策略很简单,就是从服务器中随机选择一个服务器,RandomRule的实现代码如下:

public Server choose(ILoadBalancer lb, Object key) {    if (lb == null) {        return null;    }    Server server = null;     while (server == null) {        if (Thread.interrupted()) {            return null;        }        List upList = lb.getReachableServers();        List allList = lb.getAllServers();        int serverCount = allList.size();        if (serverCount == 0) {            return null;        }        int index = rand.nextInt(serverCount); // 使用jdk内部的Random类随机获取索引值index        server = upList.get(index); // 得到服务器实例         if (server == null) {            Thread.yield();            continue;        }         if (server.isAlive()) {            return (server);        }         server = null;        Thread.yield();    }    return server;}


RoundRobinRule轮询策略表示每次都取下一个服务器,比如一共有5台服务器,第1次取第1台,第2次取第2台,第3次取第3台,以此类推:

    public Server choose(ILoadBalancer lb, Object key) {        if (lb == null) {            log.warn("no load balancer");            return null;        }         Server server = null;        int count = 0;        while (server == null && count++ < 10) {            List reachableServers = lb.getReachableServers();            List allServers = lb.getAllServers();            int upCount = reachableServers.size();            int serverCount = allServers.size();             if ((upCount == 0) || (serverCount == 0)) {                log.warn("No up servers available from load balancer: ">


WeightedResponseTimeRule继承了RoundRobinRule,开始的时候还没有权重列表,采用父类的轮询方式,有一个默认每30秒更新一次权重列表的定时任务,该定时任务会根据实例的响应时间来更新权重列表,choose方法做的事情就是,用一个(0,1)的随机double数乘以最大的权重得到randomWeight,然后遍历权重列表,找出第一个比randomWeight大的实例下标,然后返回该实例,代码略。

BestAvailableRule策略用来选取最少并发量请求的服务器:

public Server choose(Object key) {    if (loadBalancerStats == null) {        return super.choose(key);    }    List serverList = getLoadBalancer().getAllServers(); // 获取所有的服务器列表    int minimalConcurrentConnections = Integer.MAX_VALUE;    long currentTime = System.currentTimeMillis();    Server chosen = null;    for (Server server: serverList) { // 遍历每个服务器        ServerStats serverStats = loadBalancerStats.getSingleServerStat(server); // 获取各个服务器的状态        if (!serverStats.isCircuitBreakerTripped(currentTime)) { // 没有触发断路器的话继续执行            int concurrentConnections = serverStats.getActiveRequestsCount(currentTime); // 获取当前服务器的请求个数            if (concurrentConnections < minimalConcurrentConnections) { // 比较各个服务器之间的请求数,然后选取请求数最少的服务器并放到chosen变量中                minimalConcurrentConnections = concurrentConnections;                chosen = server;            }        }    }    if (chosen == null) { // 如果没有选上,调用父类ClientConfigEnabledRoundRobinRule的choose方法,也就是使用RoundRobinRule轮询的方式进行负载均衡                return super.choose(key);    } else {        return chosen;    }}


使用Ribbon提供的负载均衡策略很简单,只需以下几部:

1、创建具有负载均衡功能的RestTemplate实例

@Bean@LoadBalancedRestTemplate restTemplate() {    return new RestTemplate();}


使用RestTemplate进行rest操作的时候,会自动使用负载均衡策略,它内部会在RestTemplate中加入LoadBalancerInterceptor这个拦截器,这个拦截器的作用就是使用负载均衡。
默认情况下会采用轮询策略,如果希望采用其它策略,则指定IRule实现,如:

@Beanpublic IRule ribbonRule() {    return new BestAvailableRule();}


这种方式对Feign也有效。

我们也可以参考ribbon,自己写一个负载均衡实现类。

可以通过下面方法获取负载均衡策略最终选择了哪个服务实例:

@Autowired    LoadBalancerClient loadBalancerClient;         //测试负载均衡最终选中哪个实例    public String getChoosedService() {        ServiceInstance serviceInstance = loadBalancerClient.choose("USERINFO-SERVICE");        StringBuilder sb = new StringBuilder();        sb.append("host: ").append(serviceInstance.getHost()).append(", ");        sb.append("port: ").append(serviceInstance.getPort()).append(", ");        sb.append("uri: ").append(serviceInstance.getUri());        return sb.toString();    }

"Ribbon的负载均衡策略及原理是什么"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

服务 均衡 服务器 策略 实例 方法 权重 代码 任务 可用性 时候 均衡器 更新 情况 接口 方式 更多 机器 选择 原理 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 机架式服务器网口亮红灯 中科曙光服务器网卡在哪 网上订火车票数据库设计 手机桌面数据库打不开怎么办 莫纳什网络安全有实战吗 衡水东网软件开发 steam连接不上服务器 佰腾网专利数据库 热血传奇如何创建服务器 网易我的世界pc版1.16正在连接服务器 ipsec 访问内网服务器 企业网络安全人才的培养建议 无线网络技术期末试卷及答案 server服务器开放端口不通 网络安全专题分享 秦皇岛市公安局网络安全 运城触摸互动软件开发公司 路由器远端服务器有问题 每年九月是网络安全周吗 国际服务器代理用什么软件 山西网络技术开发售价 山东web前端软件开发服务 烟台中科网络技术研究所待遇 税务系统提示服务器无法连接 如何自建视频联网报警服务器 为什么用非关系数据库 青岛灿玛网络技术有限公司马总 软件开发相关英文 qt5数据库链接多线程 组建网络安全专业队伍
0