Ribbon负载均衡 -> 源码剖析

2,070 阅读3分钟

一、 负载均衡

负载均衡⼀般分为服务器端负载均衡和客户端负载均衡

  • 服务器端负载均衡,⽐如Nginx、F5这些,请求到达服务器之后由这些负载均衡器根据⼀定的算法将请求路由到⽬标服务器处理。
  • 谓客户端负载均衡,⽐如我们要说的Ribbon,服务消费者客户端会有⼀个服务器地址列表,调⽤⽅在请求前通过⼀定的负载均衡算法选择⼀个服务器进⾏访问,负载均衡算法的执⾏是在请求客户端进⾏。一般指微服务

二、Ribbon⾼级应⽤

  • 不需要引⼊额外的Jar坐标,因为在服务消费者中我们引⼊过eureka-client,它会引⼊Ribbon相关Jar

  • 使用:

@Bean
// Ribbon负载均衡
@LoadBalanced
public RestTemplate getRestTemplate() {
    return new RestTemplate();
}

三、Ribbon负载均衡策略

  • Ribbon内置了多种负载均衡策略,内部负责复杂均衡的顶级接⼝为 com.netflix.loadbalancer.IRule ,类树如下

  • 修改负载均衡策略
#针对的被调⽤⽅微服务名称,不加就是全局⽣效
lagou-service-resume:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule#负载策略调整

四、Ribbon核⼼源码剖析

1.Ribbon⼯作原理

Ribbon给restTemplate添加了⼀个拦截器

图中核⼼是负载均衡管理器LoadBalancer(总的协调者,相当于⼤脑,为了做事情,协调四肢),围绕它周围的多有IRule、IPing等

  • IRule:是在选择实例的时候的负载均衡策略对象
  • IPing:是⽤来向服务发起⼼跳检测的,通过⼼跳检测来判断该服务是否可⽤
  • ServerListFilter:根据⼀些规则过滤传⼊的服务实例列表
  • ServerListUpdater:定义了⼀系列的对服务列表的更新操作

2. @LoadBalanced源码剖析

我们在RestTemplate实例上添加了⼀个@LoadBalanced注解,就可以实现负载均衡,现在来来分析这个注解背后的操作(负载均衡过程)

  • 点击@LoadBalanced注解

  • SpringCloud充分利⽤了SpringBoot的⾃动装配特点,找spring.factories配置⽂件,进入org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration

  • 进入 org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration

  • 注⼊resttemplate对象到集合待⽤-> @LoadBalanced @Autowired(required = false)
  • 注⼊resttemplate定制器

  • 使⽤定制器给集合中的每⼀个resttemplate对象添加⼀个拦截器

  • 到这⾥,我们明⽩,添加了注解的RestTemplate对象会被添加⼀个拦截器LoadBalancerInterceptor,该拦截器就是后续拦截请求进⾏负载处理的。 所以,下⼀步重点我们该分析拦截器LoadBalancerInterceptor------>>>intercept()⽅法==========》》》》分析LoadBalancerInterceptor.intercept()⽅法

  • 最后执行在 org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient#execute

  • 回到 org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration#springClientFactory 这里装配了RibbonClientConfiguration

  • RibbonClientConfiguration中装配了⼤脑和肢⼲

  • com.netflix.loadbalancer.ZoneAwareLoadBalancer#chooseServer

  • 来到区域隔离策略的⽗类choose⽅法中com.netflix.loadbalancer.PredicateBasedRule#choose

  • 进入com.netflix.loadbalancer.AbstractServerPredicate#getEligibleServers()

  • 进入com.netflix.loadbalancer.AbstractServerPredicate#incrementAndGetModulo

  • 继续回到org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient#execute()

  • AbstractClientHttpRequest#execute此处,就已经到了RestTemplate底层执⾏的代码了,由此也将验证最终请求的调⽤还是靠的RestTemplate

  • 接下来,在进⾏负载chooseServer的时候,LoadBalancer负载均衡器中已经有了serverList,那么这个 serverList是什么时候被注⼊到LoadBalancer中的,它的⼀个机制⼤概是怎样的?来到RibbonClientConfiguration

  • 来到默认负载均衡策略 com.netflix.loadbalancer.ZoneAwareLoadBalancer
  • 一直super点进进来 com.netflix.loadbalancer.DynamicServerListLoadBalancer#restOfInit

  • 进⼊enableAndInitLearnNewServersFeature()⽅法,底层com.netflix.loadbalancer.DynamicServerListLoadBalancer#updateAllServerList也是CAS控制并发

  • 回到start()

3. RoundRobinRule轮询策略源码剖析

  • 来到com.netflix.loadbalancer.RoundRobinRule#choose
// 负载均衡策略类核⼼⽅法
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<Server> reachableServers = lb.getReachableServers();
            // 所有服务实例列表
            List<Server> 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: " + lb);
                return null;
            }
            // 获得⼀个轮询索引(CAS)
            int nextServerIndex = incrementAndGetModulo(serverCount);
            // 根据索引取出服务实例对象
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

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

4. RandomRule随机策略源码剖析

来到com.netflix.loadbalancer.RandomRule,跟轮训不一样就是没有循环10次就抛异常,无限循环随取,核心随机方法就是线程随机数如下:

lagouedu 笔记总结