04-Ribbon负载均衡

四、Ribbon负载均衡

前面有讲到,添加了@LoadBalanced注解,即可实现负载均衡,其原理是什么呢?

4.1、负载均衡原理

  • SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的
  • 那么我们发出的请求命名是http://userservice/user/1,怎么就变成了http://localhost:8081的呢?
  • 接下来我们简单分析一下源码

4.2、源码跟踪

为什么只输入了service名称就可以访问了呢?之前还要获取ip和端口号

  • 显然,必定有一个类或者方法帮我们根据service名称,获取到了服务实例的ip和端口
  • 它就是LoadBalancerInterceptor,这个类会对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id
  • 接下来进行源码跟踪
    • ①、全局搜索LoadBalancerInterceptor
    • ②、以debug模式运行OrderApplication
    • ③、在LoadBalancerInterceptor中的54行设置断点
    • ④、点进去execute方法,在RibbonLoadBalancerClient的116行设置断点
    • ⑤、在浏览器上再次访问

4.2.1、LoadBalancerInterceptor

  • 可以看到这里的intercept方法,拦截了用户的HttpRequest请求,然后做了如下几件事情
    • ①、request.getURI()
      • 获取请求的URI,本例中就是http://userservice/user/1
    • ②、originalUri.getHost()
      • 获取uri路径的主机名称,其实就是服务id,userservice
    • ③、this.loadBalancer.execute()
      • 处理服务id和用户请求
  • 这里的this.loadBalancerLoadBalancerClient类型。接下来继续分析

4.2.2、RibbonLoadBalancerClient

  • 进入execute方法
  • 该方法的逻辑如下所示
    • ①、getLoadBalancer(serviceId)
      • 根据服务id获取ILoadBalancer, 而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来
    • ②、getServer(loadBalancer)
      • 利用内置的负载均衡算法,从服务列表中选择一个服务(这里选到的是8082端口)
  • 放行后,再次访问并跟踪,发现获取的端口号是8083
    • 负载均衡就这样实现了!

4.2.3、负载均衡策略IRule

  • 在刚才的代码中,可以看到获取服务是通过getServer方法来做负载均衡
  • 接下来进入这个方法
  • 这里是调用了chooseServer方法,进入其方法体,发现其是属于BaseLoadBalancer类中,其方法如下所示
    • 进入到其父类中
  • 使用了这个rule变量,进行服务的选择,接下来,跟踪这个变量
  • 发现rule的默认值是一个RoundRobinRule,可以看到上面的类介绍
  • 不难发现,其就表示轮询的意思;到这里整个Ribbon的负载均衡流程就理清楚了

4.2.4、总结

  • Spring Cloud Ribbon的底层采用了一个拦截器,拦截了RestTemplate发出的请求,对地址做了修改。整体流程图如下所示
  • 基本流程
    • 1、拦截我们请求的url地址
    • 2、RibbonLoadBalancerClient会从请求url中获取服务名称,也就是userservice
    • 3、Ribbon根据服务名称到eureka拉取服务列表
    • 4、eureka返回列表:【localhost:8081、localhost:8082、localhost:8083】
    • 5、Ribbon内置有多种负载均衡策略,根接口是IRule,默认配置的是轮询策略
    • 6、经过负载均衡策略选择好服务后,返回给RibbonLoadBalancerClient
    • 7、RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1
    • 8、发送真实请求

4.3、负载均衡策略

4.3.1、负载均衡策略

  • 负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类,如下所示

  • 不同规则的含义如下表所示

    • 内置负载均衡规则类 规则描述
      RoundRobinRule 轮询规则:简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
      AvailabilityFilteringRule 可用性过滤规则:对以下两种服务器进行忽略:
      (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。
      (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit属性进行配置。
      WeightedResponseTimeRule 响应权重时间规则:为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
      ZoneAvoidanceRule 规避区域规则:以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
      BestAvailableRule 最可用规则:忽略那些短路的服务器,并选择并发数较低的服务器。
      RandomRule 随机规则:随机选择一个可用的服务器。
      RetryRule 重试实现:重试机制的选择逻辑

      默认的实现就是ZoneAvoidanceRule,是一种轮询方案

4.3.2、自定义负载均衡策略

  • 如果不想使用系统默认的策略,也可以使用以下方式自己选择不同的策略,通过定义IRule实现可以修改负责均衡规则。主要有两种方式可以实现

  • 1、代码方式

    • ①、在order-service中的OrderApplication类中,定义一个新的IRule

      •     /**
             * 自定义负载均衡:这种方式是全局的配置,无论以后访问哪个微服务都使用随机的方式
             */
            @Bean
            public IRule iRule() {
                System.out.println("选择随机的负载均衡策略");
                return new RandomRule();
            }
        
    • ②、重新启动OrderApplication

    • ③、刷新网页,访问六次

    • ④、查看UserApplication的控制台是哪个控制台数据SQL语句,会发现是随机的选择不同的服务器

      • 本次个人测试是3次8081,3次8083,8082端口没有被访问
  • 2、配置文件方式

    • ①、注释掉OrderApplication中规则的方法,这时又还原成轮询的方式

    • ②、在order-service的application.yml文件中,添加新的配置规则,userservice是顶层元素

      • # 给某个微服务配置负载均衡规则,只对这个微服务起作用
        userservice:
          ribbon:
            # 负载均衡规则的类全名
            NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
        
        
    • 不过一般是使用默认的负载均衡规则,不需要修改

4.3.3、小结

  • 修改负载均衡规则的方式
    • 1、编码方式
      • 特点是全局应用
    • 2、配置文件方式
      • 特点是针对指定的服务定义的负载均衡策略

4.4、饥饿加载

  • Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长;下面是演示过程

    • 1、重启OrderApllication服务器
    • 2、在浏览器访问,并且显示第1次和第2次访问的时长
      • 第一次访问
      • 第二次访问
    • 3、在服务器端的控制台也能见到相应的信息
  • 饥饿加载的配置

    • 1、饥饿加载会在项目启动的时候创建,降低第一次访问的耗时,通过下面配置开启饥饿加载(ribbon是顶层元素)

      • ribbon:
          eager-load:
            enabled: true  # 开启饥饿加载
            clients:
              - userservice  # clients是一个List集合。如果要配置多个服务名字,则换一行。用-做为前缀,每行写一个
        
    • 2、再次重启OrderApplication,会发现一启动就加载了负载均衡的服务

    • 3、查看浏览器访问时间,时间少了一半

posted @ 2022-07-11 16:25  OnlyOnYourself-Lzw  阅读(34)  评论(0编辑  收藏  举报