【微服务SpringCloud】:Ribbon 详解

文章目录

    • 1、什么是 Ribbon ?
    • 2、什么是负载均衡 ?
    • 3、Ribbon 中的组件
    • 4、Rule 组件
    • 5、实现负载均衡
      • 5.1、单独使用 Ribbon
      • 5.2、与注册中心配合使用
      • 5.3、重试
    • 6、注解 @LoadBalanced
    • 7、Ribbon懒加载

1、什么是 Ribbon ?

Ribbon 是 Netflixfa 发布的一个负载均衡器,主要用于控制 HTTP 和 TCP客户端行为

Ribbon 有两个主要作用:

  • 服务调用:基于 Ribbon 实现服务调用, 是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助 RestTemplate 最终进行调用
  • 负载均衡:当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址

在服务消费方通过 RestTemplate 调用微服务的时候,会拼接服务的访问地址等信息,如下所示:
【微服务SpringCloud】:Ribbon 详解_第1张图片
这种方式虽然可以,但是不太方便。所以可以使用 Ribbon 的服务调用来解决,在后面我们去了解具体使用方法。

Ribbon 可以单独使用,但是大多数情况下在 SpringCloud 中使用,配合注册中心进行使用。

2、什么是负载均衡 ?

负载均衡是一种基础的网络服务,按照指定的负载均衡算法,将流量分配到后端服务集群上,从而为系统提供并行扩展的能力。

  • 服务端负载均衡:发送请求到服务器,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;即在服务器端再进行负载均衡算法分配
  • 客户端负载均衡:客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问;即在客户端就进行负载均衡算法分配,Ribbon 就是一个客户端负载均衡器

在微服务中要保持系统的高可用行,所以将多个相同的服务提供者注册到注册中心上,那么服务消费者需要具体的选择服务提供者,这个过程就由 Ribbon 中的负载均衡完成。

3、Ribbon 中的组件

Ribbon 的关键组件如下:

  • ServerList:可以响应客户端的特定服务的服务器列表。

    .ribbon.NIWSServerListFilterClassName配置项可以配置获取服务器的方法,在默认情况使用的是ConfigurationBasedServerList类,这个类可以从配置文件中获取所有服务列表:

    #这个名称表示具体的服务
    #供 RestTemplate 类去调用,如果省略服务名称则表示配置作用在所有的服务中,
    服务名称: 
    	ribbon: 
    		listOfServers: www.microsoft.com:80,www.yahoo.com:80,www.google.com:80
    

    但是配合注册中心时,服务列表是从注册中心获取的,所以上述配置可以省略,这时使用的是DiscoveryEnabledNIWSServerList类。

  • ServerListFilter:可以动态获得的具有所需特征的候选服务器列表的过滤器。

    .ribbon.NIWSServerListFilterClassName配置项可以配置过滤器使用的类,默认使用ZonePreferenceServerListFilter

  • ServerListUpdater:用于执行动态服务器列表更新。

  • Rule:负载均衡策略,用于确定从服务器列表返回哪个服务器。

    .ribbon.NFLoadBalancerRuleClassName配置项可以配置负载均衡策略使用的类,默认使用ZoneAvoidanceRule

  • Ping:客户端用于快速检查服务器当时是否处于活动状态。

    .ribbon.NFLoadBalancerPingClassName配置项可以配置检查服务器使用的类,默认使用DummyPing类,当和注册中心配合使用时,使用的是NIWSDiscoveryPing

  • LoadBalancer:负载均衡器,负责负载均衡调度的管理。将以上组件组合到这个类中一起工作。

    .ribbon.NFLoadBalancerClassName配置项可以配置负载均衡器使用的类,默认使用ZoneAwareLoadBalancer

在上述几个组件中,最需要关注的就是 Rule 组件。

4、Rule 组件

Rule 组件用于负载均衡策略,Ribbon 提供了一个 IRule 接口是 Ribbon 中负载均衡的顶级接口。IRule 接口中定义了选择负载均衡策略的基本操作,可以通过配置文件或者配置类选择具体的负载均衡策略。

策略 名称 说明
com.netflix.loadbalancer.RoundRobinRule 轮询策略 按顺序选择服务,默认就是这种服务。
com.netflix.loadbalancer.RandomRule 随机策略 随机选择服务
com.netflix.loadbalancer.RetryRule 重试策略 在一个时间段选择服务失败,则选择尝试一个可用服务
com.netflix.loadbalancer.WeightedResponseTimeRule 权重策略 会计算每个服务的权重,越高的被调用的可能性越大。
com.netflix.loadbalancer.BestAvailableRule 最佳策略 遍历所有的服务实例,过滤掉故障实例,并返回请求数最小的实例返回。
com.netflix.loadbalancer.AvailabilityFilteringRule 可用过滤策略 过滤掉故障和请求数超过阈值的服务实例,再从剩下的实力中轮询调用
com.netflix.loadbalancer.ZoneAvoidanceRule 复合策略 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个 zone的运行性能是否可用,剔除不可用的zone,后一个用于过滤掉连接数过多的 Server。

5、实现负载均衡

5.1、单独使用 Ribbon

  • 引入依赖:如果不配和注册中心使用,那么需要单独引用 Ribbon 的依赖。
    <dependencies>	
    	
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
            <version>版本号version>
        dependency>
    dependencies>
    
  • 修改启动类:向 IOC 容器中注入 RestTemplate 类,并添加 @LoadBalanced注解
    @SpringBootApplication
    public class Application {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    
        public static void main(String[] args)
        {
           SpringApplication.run(Application.class, args);
        }
    }
    
  • 修改配置文件:在配置文件中添加有关 Ribbon 的设置
    #microservice-provider-user 表示需要调用的服务名
    eurek-user-service:
      ribbon:
        listOfServers: localhost:9003,localhost:9004,localhost:9005
    
  • 具体使用:在使用``调用服务的时候,IP地址是一个字符串,不同于之前的具体的地址,这就是使用 Ribbon 的好处。
    @RestController
    @RequestMapping("/order")
    public class orderController {
    	
        @Autowired
        private RestTemplate restTemplate;
    
        @RequestMapping(value = "/buy", produces = "text/plain;charset=UTF-8")
        @ResponseBody
        public String buy(int id) throws IOException {
        	//这里的"http://microservice-provider-user/product/在没有使用 Ribbon之前,应该是 "http://localhost:9003/product/
        	//在使用了 Ribbon 之后就直接与配置文件中的配置对应,自动完成负载均衡
            return this.restTemplate.getForObject("http://microservice-provider-user/product/"+id,String.class);
        }
    

5.2、与注册中心配合使用

  • 引入依赖:当与注册中心使用时,可以省略对 Ribbon 依赖的导入,因为 Consul 和 Eureka 中已经含有 Ribbon 依赖。
  • 修改启动类:向 IOC 容器中注入 RestTemplate 类,并添加 @LoadBalanced注解
    @SpringBootApplication
    @EnableEurekaClient
    public class OrderMain{
    
        public static void main(String[] args)
        {
           SpringApplication.run(OrderMain.class, args);
        }
        
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
    
  • 设置赋值均衡策略:Ribbon 默认使用的是轮询策略,也可以通过如下配置替换轮询策略
    eurek-user-service:
     ribbon:
       NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    
  • 具体使用:
    @RestController
    @RequestMapping("/order")
    public class orderController {
    
    	//省略了获取元数据的步骤
    	//@Autowired
        //private DiscoveryClient discoveryClient;
        
        @Autowired
        private RestTemplate restTemplate;
    
        @RequestMapping(value = "/buy", produces = "text/plain;charset=UTF-8")
        @ResponseBody
        public String buy(int id) throws IOException {
        	//省略了获取元数据的步骤,在 restTemplate 进行访问的时候
        	//去注册中心寻找 microservice-provider-user 这个服务,然后进行负载均衡,返回一个正在的 IP 地址
            return this.restTemplate.getForObject("http://microservice-provider-user/product/"+id,String.class);
        }
    

5.3、重试

为了保证微服务的高可用,一般服务都是以集群的形式注册到注册中心,所以就需要 Ribbon 进行负载均衡。当消费者去调服务时, 通过 Ribbon 返回了一个具体的服务地址。当这个服务出现问题无法访问时,服务消费者会出现异常。为了解决这个问题,Ribbon 引入了重试机制,当消费者请求失败时,会根据配置进行重新发起请求。

  • 引入依赖:想要实现重试必须导入如下所示依赖,当引入这个依赖之后,就能进行重试了
    <dependency>
       <groupId>org.springframework.retrygroupId>
       <artifactId>spring-retryartifactId>
    dependency>
    
  • 添加重试配置:重试的配置 Ribbon 已经配置了,但是可以通过如下配置项覆盖默认的配置。
    #service-product5表示服务名,根据个人服务进行配置,没有固定值
    service-product5:
      ribbon:
        ConnectTimeout: 250 # Ribbon的连接超时时间
        ReadTimeout: 1000 # Ribbon的数据读取超时时间
        OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
        MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
        MaxAutoRetries: 1 # 对当前实例的重试次数
    

6、注解 @LoadBalanced

在使用负载均衡的过程中,我们就在启动类中添加了一个@LoadBalanced注解,这个注解主要用于给RestTemplate类添加一个 LoadBalancerClient接口的实现类,而这个类就是实现负载均衡的关键。

下面我们对整个流程进行解析:

  • 在启动项目时,会引入LoadBalancerAutoConfiguration配置类,这个类 Ribbon 中负载均衡的配置类。【微服务SpringCloud】:Ribbon 详解_第2张图片
    我们重点关注下列这个方法:

    @Bean
    @ConditionalOnMissingBean
    public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
        return (restTemplate) -> {
            List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
        };
    }
    

    上述方法中:

    • LoadBalancerInterceptor类,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。
    • RestTemplateCustomizer类,用于给 RestTemplate 增加 LoadBalancerInterceptor 拦截器。
    • 通过调用 RestTemplateCustomizer 实例来给客户端负载均衡中被 @LoadBalanced注解修饰的 RestTemplate 对象列表增LoadBalancerInterceptor 拦截器。
  • LoadBalancerInterceptor拦截器:

    【微服务SpringCloud】:Ribbon 详解_第3张图片
    在这个类中实例化了一个LoadBalancerClient接口的实现,LoadBalancerClient只是一个负载均衡器接口。

    当一个被 @LoadBalanced 注解修饰的 RestTemplate 对象向外发起HTTP请求时,会被LoadBalancerInterceptor 类的 intercept 函数所拦截。从 HttpRequest 的 URI 对象中通过 getHost() 就可以拿到服务名,然后根据服务名来选择实例并发起实际的请求。

  • BlockingLoadBalancerClientRibbonLoadBalancerClient都是接口的实现类

    【微服务SpringCloud】:Ribbon 详解_第4张图片

7、Ribbon懒加载

Ribbon 在进行客户端负载均衡的时候并不是在启动的时候就加载,实在实际请求的时候才加载,这回导致第一次请求会比较的缓慢,甚至可能会出现超时的情况。所以我们可以指定具体的客户端名称来开启懒加载,即在启动的时候便加载素养的配置项的应用上下文。

具体服务名:
  eager-load:
    enabled: true
    clients: ribbon-client-a, ribbon-client-b, ribbon-client-c

你可能感兴趣的:(SpringCloud,spring,cloud,微服务,ribbon)