SpringCLoud-Ribbon源码分析

 2023-01-25
原文作者:lcw2013 原文地址:https://juejin.cn/post/7017271165601185806

Ribbon负载均衡

1.1 关于负载均衡

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

所谓 服务器端负载均衡 ,⽐如Nginx、F5这些,请求到达服务器之后由这些负载均衡 器根据⼀定的算法将请求路由到⽬标服务器处理。

所谓 客户端负载均衡 ,⽐如我们要说的Ribbon,服务消费者客户端会有⼀个服务器 地址列表,调⽤⽅在请求前通过⼀定的负载均衡算法选择⼀个服务器进⾏访问,负 载均衡算法的执⾏是在请求客户端进⾏。

Ribbon是Netflflix发布的负载均衡器。Eureka⼀般配合Ribbon进⾏使⽤,Ribbon利 ⽤从Eureka中读取到服务信息,在调⽤服务提供者提供的服务时,会根据⼀定的算 法进⾏负载。

202301012121118681.png

1.2 Ribbon⾼级应⽤

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

202301012121125152.png 代码中使⽤如下,在RestTemplate上添加对应注解即可

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

1.3 Ribbon负载均衡策略

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

202301012121132193.png 负载均衡策略

  • RoundRobinRule:轮询策略;默认超过10次获取到的server都不可⽤,会返回⼀个空的server 修改负载均衡策略
    #针对的被调⽤⽅微服务名称,不加就是全局⽣效
    lagou-service-resume:
      ribbon:
        NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule #负载策略调整

1.4 Ribbon核⼼源码剖析

Ribbon⼯作原理

202301012121142204.png 重点:Ribbon给restTemplate添加了⼀个拦截器

思考:Ribbon在做什么: 当我们访问http://lagou-service-resume/resume/openstate/ 的时候,ribbon应该根据服务名lagou-service-resume获取到该服务的实例列表并按照⼀定的负载均衡 策略从实例列表中获取⼀个实例Server,并最终通过RestTemplate进⾏请求访问

Ribbon细节结构图(涉及到底层的⼀些组件/类的描述)

202301012121160345.png

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

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

1.4.1 @LoadBalanced源码剖析

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

1.4.1.1查看@LoadBalanced注解,那这个注解是在哪⾥被识别到的呢?

使用@LoadBalanced注解后可以将普通的RestTemplate对象使用LoadBalancerClient去处理

    @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Qualifier
    public @interface LoadBalanced {
    }

1.4.1.2LoadBalancerClient类(实现类RibbonLoadBalancerClient,待⽤)

    public interface LoadBalancerClient extends ServiceInstanceChooser {
        // 根据服务执行请求内容
       <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
        // 根据服务执行请求内容
       <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
        // 拼接请求方式 传统中是ip:port 现在是服务名称:port形式
       URI reconstructURI(ServiceInstance instance, URI original);
    }

1.4.1.3SpringCloud充分利⽤了SpringBoot的⾃动装配特点,找spring.factories配置⽂件

202301012121168046.png