Spring Cloud 入门(5):Ribbon的定义,配置策略,超时重置,饥饿加载

Ribbon 是什么

Ribbon 是一个客户端负载均衡器,它赋予了应用一些支配HTTP 与 TCP 行为的能力,这里的负载均衡是客户端的负载均衡,也有人称为后端负载均衡是进程内负载均衡的一种。

  • 前面分析了 Eureka 的使用,作为服务注册中心,Eureka 分为 Server 端和 Client 端,Client 端作为服务的提供者,将自己注册到 Server 端,Client 端高可用的方式是使用多机部署然后注册到 Server,Server 端为了保证服务的高可用,也可以使用多机部署的方式。
  • 前面简单搭建了Eureka Client 和 Server,然后将Client成功注册到 Server,本节我们将来看看如何调用Eureka 服务,在多机部署情况下如何保证负载均衡。Spring Cloud 提供了一个组件:Ribbon。
  • Ribbon是客户端负载均衡器,可以对 HTTP 和 TCP 客户端的行为进行大量控制。Ribbon中的中心概念是指定客户端的概念。

Ribbon API

服务端负载均衡

  • 服务端负载均衡。将多个服务注册到一个公共的注册中心,服务调用者访问注册中心,由注册中心提供服务的负载均衡。
    在这里插入图片描述

客户端负载均衡:
在这里插入图片描述

服务端负载均衡的代表性例子就是nginx,LVS。那么客户端的负载均衡就是我们要说的Ribbon。Ribbon主要提供客户端负载平衡算法,除此之外,Ribbon还提供:

  • 服务发现集成 : 功能区负载平衡器在动态环境(如云)中提供服务发现。功能区库中包含与Eureka和Netflix服务发现组件的集成;
  • 容错 : Ribbon API 可以动态确定服务器是否已在实时环境中启动并运行,并且可以 检测到那些已关闭的服务器;
  • 可配置的负载平衡规则 : Ribbon支持开箱即用的 RoundRobinRule,AvailabilityFilteringRule,WeightedResponseTimeRule,还支持定义自定义规则。

Ribbon API

  • Rule :定义负载均衡策略;
  • Ping : 定义如何 ping 目标服务实例来判断是否存活, ribbon 使用单独的线程每隔一段时间(默认10s)对本地缓存的 ServerList 做一次检查;
  • ServerList :定义如何获取服务实例列表. 两种实现基于配置的 ConfigurationBasedServerList 和基于Eureka 服务发现的 DiscoveryEnabledNIWSServerList
  • ServerListFilter: 用来使用期望的特征过滤静态配置,动态获得的候选服务实例列表. 若未提供, 默认使用ZoneAffinityServerListFilter;
  • ILoadBalancer: 定义了软负载均衡器的操作的接口。一个典型的负载均衡器至少需要一组用来做负载均衡的服务实例;
  • ServerListUpdater: DynamicServerListLoadBalancer用来更新实例列表的策略(推EurekaNotificationServerListUpdater/拉PollingServerListUpdater, 默认是拉)

Ribbon 的搭建

由于客户端负载均衡需要从注册中心获取服务列表,所以需要集成注册中心。

创建注册中心

  • 创建父级工程 cloud-ribbon-practice

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.cloud-version>Hoxton.SR3</spring.cloud-version>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
  • 创建注册中心 cloud-eureka-server

    <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
    
  • 配置文件 application.yaml

    server:
      port: 8761
    eureka:
      instance:
        hostname: localhost
      client:
        registerWithEureka: false
        fetchRegistry: false
        serviceUrl:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
  • 启动类

    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaServerApplication.class, args);
        }
    }
    

创建源服务的提供者 cloud-ribbon-hello-b1、cloud-ribbon-hello-b2、cloud-ribbon-hello-b3

  • 每个工程都引入 Eureka

    <dependencies>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
         </dependency>
     </dependencies>
    
  • 配置文件 application.xml
    b1

    spring:
      application:
        name: ribbon-service-b
    server:
      port: 7777
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true
    

    b2

    spring:
      application:
        name: ribbon-service-b
    server:
      port: 7778
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true
    

    b3

    	spring:
      application:
        name: ribbon-service-b
    server:
      port: 7779
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true
    
  • b1、b2、b3的controller

    @RestController
    public class OrderController {
    
        @Value("${server.port}")
        private Integer port;
    
        @Value("${spring.application.name}")
        private String name;
    
        @GetMapping("/test")
        public String add() {
            return "this service name is " + name + " and port is " + port;
        }
    
    }
    
  • b1、b2、b3的启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    public class ServiceB1Application {
        public static void main(String[] args) {
            SpringApplication.run(ServiceB1Application.class, args);
        }
    }
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ServiceB2Application {
        public static void main(String[] args) {
            SpringApplication.run(ServiceB2Application.class, args);
        }
    }
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ServiceB3Application {
        public static void main(String[] args) {
            SpringApplication.run(ServiceB3Application.class, args);
        }
    }
    

创建服务的调用者 cloud-ribbon-hello-a

  • spring-cloud-starter-netflix-eureka-client 已经集成了 ribbon。不需要额外引入,直接使用即可。

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    

    -

  • 配置文件 application.yml

    spring:
      application:
        name: ribbon-hello-a
    server:
      port: 7776
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true
    

    启动类,RestTemplate 使用了@LoadBalanced,这样 RestTemplate 就开启了 ribbon 的负载均衡了。

    @SpringBootApplication
    @EnableDiscoveryClient
    public class ServiceAApplication {
        public static void main(String[] args) {
            SpringApplication.run(ServiceAApplication.class, args);
        }
    
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    controller
    
    @RestController
    @RequestMapping("ribbon")
    public class TestController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping("/test")
        public String test(){
            String body = restTemplate.getForEntity("http://RIBBON-SERVICE-B/test", String.class).getBody();
            return body;
        }
    
    }
    

测试

  • 测试,使用postman访问几次:http://localhost:7776/ribbon/...
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

Ribbon 的服务策略配置

策略配置参数

从上一节可以看到,开启负载均衡只需通过@LoadBalanced注解即可。

  • 定义一个负载均衡的 RestTemplate,使用了 @LoadBalanced注解,该注解配合覆盖均衡策略一起使用 RestTemplate 发出的请求才能生效。

可以根据实际的业务场景选择最合适的策略:

策略类命名描述
RandomRule随机策略随机选择Server
RoundRobinRule轮询策略按顺序选择Server
RetryRule重试策略在一个配置时间段内当选择 Server 不成功,则一直尝试选择一个可用的Server
BestAvailableRule最低并发策略先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
AvailabilityFilteringRule可用过滤策略过滤一直连接失败并标记为circuit tripped的Server,过滤掉那些高并发连接的Server(active connections超过配置的阈值)
ResponseTimeWeightedRule响应时间加权策略已经被弃用,作用同WeightedResponseTimeRule
WeightedResponseTimeRule响应时间加权策略根据Server的响应时间分配权重,响应时间越长,权重越低,被选中的概率就越低。响应时间越短,权重越高,被选择到的概率越高
ZoneAvoidanceRule区域权衡策略综合判断 Server 所在区域的性能和Server 的可用性轮询选择 Server,并且判断一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中 的所有 Server

配置方式

全局配置

  • 使用 Ribbon 时配置全局的负载均衡策略,需要加一个配置类。该配置类需要被 @ComponentScan 扫描到才能全局生效。

    @Configuration
    public class GlobalRuleConfig {
        @Bean
        public IRule ribbonRule() {
            return new RandomRule();
        }
    }
    

    上面配置了随机的策略,多次访问http://localhost:7776/ribbon/...

基于 @RibbonClient@RibbonClients注解的配置

注意:编写自定义配置类,需要特别注意的是官方文档明确给出了警告:这个自定义配置类不能放在@ComponentScan所扫描的包以及其子包下(即不能放在主启动类所在的包及其子包下,因此我们需要新建一个包来放该配置类),否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就达不到特殊化定制的目的了

  • 策略配置

    @Configuration
    public class AnnoRuleConfig {
        @Bean
        public IRule ribbonRule() {
            return new RandomRule();
        }
    }
    
  • 启动类的配置

    @SpringBootApplication
    @EnableDiscoveryClient
    @RibbonClient(name = "ribbon-service-b", configuration = AnnoRuleConfig.class)
    public class ServiceAApplication {
        public static void main(String[] args) {
            SpringApplication.run(ServiceAApplication.class, args);
        }
    
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    
    • 通过 @RibbonClient 指定某个服务的负载均衡策略,其他没有被指定的,就是用默认的负载均衡策略。
  • @RibbonClient 注解可以把其他的配置类作为另外一个IOC容器导入到应用中,相当于加载了两个完全不相干的 Spring 的 beans 配置文件,此时应用中会有两个IOC容器。

    @RibbonClient(name = "RIBBON-SERVICE-B", configuration = AnnoRuleConfig.class)
    
  • 也可以使用 RibbonClients 指定多个服务的负载均衡策略

    @RibbonClients(value = {
            @RibbonClient(name = "RIBBON-SERVICE-B", configuration = AnnoRuleConfig.class),
            @RibbonClient(name = "RIBBON-SERVICE-C", configuration = AnnoRuleConfig.class)
    })
    

基于配置文件

  • 下面对服务 ribbon-service-b 的负载均衡策略使用

    RIBBON-SERVICE-B:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    

Ribbon 超时与重试

使用 HTTP 发起请求难免会发生问题,在F版开始 Ribbon 的重试机制默认是开启的,需要添加对超时时间与重试策略的配置。

  • 列如下面 ribbon-service-b 服务的配置

    RIBBON-SERVICE-B:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
        ConnectTimeout: 3000
        ReadTimeout: 60000
        MaxAutoRetries: 3 #对第一次请求的服务的重试次数
        MaxAutoRetriesNextServer: 1 #要重试的下一个服务的最大数量(不包括第一个服务)
        OkToRetryOnAllOperations: true
    
  • 也可以全局配置

    ribbon:
      ConnectTimeout: 3000
      ReadTimeout: 60000
      MaxAutoRetries: 3 #对第一次请求的服务的重试次数
      MaxAutoRetriesNextServer: 1 #要重试的下一个服务的最大数量(不包括第一个服务)
      OkToRetryOnAllOperations: true
    
  • 一般 Ribbon 都是搭配 OpenFeign 这类 Http 客户端或者其他RPC 使用。因为这样去调用远程服务会更加优雅和方便。而OpenFeign默认是继承了Ribbon,对于Ribbon的超时时间配置也是很简单。

  • 对于网络抖动这些可以使用spring-retry,spring-retry是spring提供的一个基于spring的重试框架,非常好用。

Ribbon 饥饿加载

Ribbon 在进行客户端负载均衡的时候,并不是启动时就加载上下文,而是在实际请求的时候采取创建。

  • 因为要加载上下文的原因,在第一次调用时可能会很慢,甚至导致超时。

  • 所以我们可以指定 Ribbon 客户端开启立即加载(饥饿加载),在应用启动的时候就立即加载所有配置项的应用程序上下文。

    ribbon:
      eager-load:
        clients: ribbon-service-b, ribbon-service-order
        enabled: true
    

Eureka 在 Ribbon 的作用

下面看一下整合 Eureka 和 Ribbon 如何实现服务调用 和 负载均衡。有了 Eureka 之后,服务调用就无需关注服务提供者的IP
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值