个人 二维码




公众号二维码

name - artist
00:00

      目录

      Spring Cloud 系列之 Netflix Ribbon 负载均衡

      什么是 Ribbon

        

        Ribbon 是一个基于 HTTP 和 TCP 的 客服端负载均衡工具,它是基于 Netflix Ribbon 实现的。

        它不像 Spring Cloud 服务注册中心、配置中心、API 网关那样独立部署,但是它几乎存在于每个 Spring Cloud 微服务中。包括 Feign 提供的声明式服务调用也是基于该 Ribbon 实现的。

        Ribbon 默认提供很多种负载均衡算法,例如轮询、随机等等。甚至包含自定义的负载均衡算法。

        

      Ribbon 解决了什么问题

        

        Ribbon 提供了一套微服务的负载均衡解决方案。

        

      负载均衡不同方案的区别

        

        目前业界主流的负载均衡方案可分成两类:

      • 集中式负载均衡(服务器负载均衡),即在 consumer 和 provider 之间使用独立的负载均衡设施(可以是硬件,如 F5,也可以是软件,如 nginx),由该设施负责把访问请求通过某种策略转发至 provider;
      • 进程内负载均衡(客户端负载均衡),将负载均衡逻辑集成到 consumer,consumer 从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的 provider。Ribbon 属于后者,它只是一个类库,集成于 consumer 进程,consumer 通过它来获取 provider 的地址。

        

      集中式负载均衡

        

      /resources/articles/spring/spring-cloud/ribbon/u=708889431,483252920&fm=26&gp=0.jpg

        

      进程内负载均衡

        

      /resources/articles/spring/spring-cloud/ribbon/1578386040836.png

        

      Ribbon 负载均衡策略

        

      轮询策略(默认)

        

        策略对应类名:RoundRobinRule

        实现原理:轮询策略表示每次都顺序取下一个 provider,比如一共有 5 个 provider,第 1 次取第 1 个,第 2 次取第 2 个,第 3 次取第 3 个,以此类推。

        

      权重轮询策略

        

        策略对应类名:WeightedResponseTimeRule

        实现原理:

      • 根据每个 provider 的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低。
      • 原理:一开始为轮询策略,并开启一个计时器,每 30 秒收集一次每个 provider 的平均响应时间,当信息足够时,给每个 provider 附上一个权重,并按权重随机选择 provider,高权越重的 provider 会被高概率选中。

        

      随机策略

        

        策略对应类名:RandomRule

        实现原理:从 provider 列表中随机选择一个。

        

      最少并发数策略

        

        策略对应类名:BestAvailableRule

        实现原理:选择正在请求中的并发数最小的 provider,除非这个 provider 在熔断中。

        

      重试策略

        

        策略对应类名:RetryRule

        实现原理:其实就是轮询策略的增强版,轮询策略服务不可用时不做处理,重试策略服务不可用时会重新尝试集群中的其他节点。

        

      可用性敏感策略

        

        策略对应类名:AvailabilityFilteringRule

        实现原理:过滤性能差的 provider

      • 第一种:过滤掉在 Eureka 中处于一直连接失败的 provider。
      • 第二种:过滤掉高并发(繁忙)的 provider。

        

      区域敏感性策略

        

        策略对应类名:ZoneAvoidanceRule

        实现原理:

      • 以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下区域中选可用的 provider。
      • 如果这个 ip 区域内有一个或多个实例不可达或响应变慢,都会降低该 ip 区域内其他 ip 被选中的权 重。

        

      Ribbon 入门案例

        

        eureka-demo 聚合工程。SpringBoot 2.2.4.RELEASESpring Cloud Hoxton.SR1

        Ribbon 中对于集群的服务采用的负载均衡策略默认是轮询。

        

      创建项目

        

        使用学习 Eureka 时的 eureka-demo 项目,在该项目中创建子项目 service-provider02

      /resources/articles/spring/spring-cloud/ribbon/1578836785223.png

      /resources/articles/spring/spring-cloud/ribbon/image-20200213131503574.png

      /resources/articles/spring/spring-cloud/ribbon/image-20200213131548627.png

      /resources/articles/spring/spring-cloud/ribbon/image-20200213131647813.png

      /resources/articles/spring/spring-cloud/ribbon/1578826063614.png

        

      添加依赖

        

        pom.xml

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      
      <?xml version="1.0" encoding="UTF-8"?>
      
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.example</groupId>
          <artifactId>service-provider02</artifactId>
          <version>1.0-SNAPSHOT</version>
      
          <!-- 继承父依赖 -->
          <parent>
              <groupId>com.example</groupId>
              <artifactId>eureka-demo</artifactId>
              <version>1.0-SNAPSHOT</version>
          </parent>
      
          <!-- 项目依赖 -->
          <dependencies>
              <!-- netflix eureka client 依赖 -->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
              </dependency>
              <!-- spring boot web 依赖 -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <!-- lombok 依赖 -->
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <scope>provided</scope>
              </dependency>
              <!-- spring boot actuator 依赖 -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
      
              <!-- spring boot test 依赖 -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
                  <scope>test</scope>
                  <exclusions>
                      <exclusion>
                          <groupId>org.junit.vintage</groupId>
                          <artifactId>junit-vintage-engine</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
          </dependencies>
        
      </project>
      

        

      配置文件

        

        application.yml

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      
      server:
        port: 7071 # 端口
      
      spring:
        application:
          name: service-provider # 应用名称(集群下相同)
      
      # 配置 Eureka Server 注册中心
      eureka:
        instance:
          prefer-ip-address: true       # 是否使用 ip 地址注册
          instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
        client:
          service-url:                  # 设置服务注册中心地址
            defaultZone: http://root:123456@localhost:8761/eureka/,http://root:123456@localhost:8762/eureka/
      
      # 度量指标监控与健康检查
      management:
        endpoints:
          web:
            exposure:
              include: shutdown         # 开启 shutdown 端点访问
        endpoint:
          shutdown:
            enabled: true               # 开启 shutdown 实现优雅停服
      

        

      服务及启动类

        

        将所有代码复制粘贴一份至 server-provider02,修改启动类名称即可。

        ServiceProvider02Application.java

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      
      package com.example;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      @SpringBootApplication
      public class ServiceProvider02Application {
      
          public static void main(String[] args) {
              SpringApplication.run(ServiceProvider02Application.class, args);
          }
      
      }
      

      为了更直观的看到负载均衡的效果,我们在 service-consumer 项目中将服务地址打印至控制台。

        

      注册中心

        

        运行完整的 Eureka 环境,访问:http://localhost:8761/ 可以看到现在已经有两个服务提供者。

      /resources/articles/spring/spring-cloud/ribbon/1578826530501.png

        

      消费服务

        

        多次访问:http://localhost:9090/order/1 可以看到默认使用的是轮询策略。

      /resources/articles/spring/spring-cloud/ribbon/image-20200213133242054.png

        

      Ribbon 负载均衡策略设置

        

      全局

        

        在启动类或配置类中注入负载均衡策略对象。所有服务请求均使用该策略。

      1
      2
      3
      4
      
      @Bean
      public RandomRule randomRule() {
          return new RandomRule();
      }
      

        多次访问:http://localhost:9090/order/1 结果如下:

      /resources/articles/spring/spring-cloud/ribbon/image-20200213133444394.png

        

      局部

        

        修改配置文件指定服务的负载均衡策略。格式:服务应用名.ribbon.NFLoadBalancerRuleClassName

      1
      2
      3
      4
      5
      
      # 负载均衡策略
      # service-provider 为调用的服务的名称
      service-provider:
        ribbon:
          NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
      

        多次访问:http://localhost:9090/order/1 结果如下:

      /resources/articles/spring/spring-cloud/ribbon/image-20200213133714557.png

        

      Ribbon 点对点直连

        

        点对点直连是指绕过注册中心,直接连接服务提供者获取服务,一般在测试阶段使用比较多。

        

      添加依赖

        

        在调用方 pom 文件中引入 ribbon 依赖,需要注意的是如果 pom 中有 Eureka 的依赖,则需要去除 Eureka 的依赖。

      1
      2
      3
      4
      5
      
      <!-- netflix ribbon 依赖 -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
      </dependency>
      

        

      配置文件

        

        配置文件中关闭 Eureka,添加直连的服务地址。如果不设置负载均衡策略默认使用轮询策略。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      # 负载均衡策略
      # service-provider 为调用的服务的名称
      service-provider:
        ribbon:
          NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
          # 点对点直连模式,指定具体的 Provider 服务列表,多个用逗号隔开
          listOfServers: http://localhost:7070,http://localhost:7071
      
      # 关闭 Eureka 实现 Ribbon 点对点直连
      ribbon:
        eureka:
          enabled: false # false:关闭,true:开启
      

        

      访问

        

        关闭 Eureka 注册中心,服务提供者由于无法连接至注册中心所以会报连接异常。但是服务是可以正常可消费的,所以目前使用的是点对点的方式来进行调用的。

        多次访问:http://localhost:9090/order/1 结果如下:

      /resources/articles/spring/spring-cloud/ribbon/image-20200213134023692.png

        至此 Ribbon 负载均衡所有的知识点就讲解结束了。

      /resources/articles/articles_bottom/end02.gif

      本文采用 知识共享「署名-非商业性使用-禁止演绎 4.0 国际」许可协议

      大家可以通过 分类 查看更多关于 Spring Cloud 的文章。

        

      🤗 您的点赞转发是对我最大的支持。

      📢 扫码关注 哈喽沃德先生「文档 + 视频」每篇文章都配有专门视频讲解,学习更轻松噢 ~

      /resources/mrhelloworld/qrcode/OfficialAccounts500-500.gif

      「 感谢支持 」
       评论