Spring Cloud之Ribbon负载均衡(Spring Cloud 2020.0.3版)

Spring Cloud Ribbon

demo代码放在github上 ,需要的请点这里--> demo

1. Ribbon简介

一般来说,在生产环境中,各个微服务都会部署多个实例。那么消费者要如何将请求分摊到多个服务提供者实例上呢?负载均衡在系统架构中一个非常重要,不得不去实施的内容,负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。通常所说的负载均衡都是指服务端负载均衡,其中分为硬件负载均衡(如F5)和软件负载均衡(如Nginx)。Ribbon是NetFlix发布的客户端负载均衡器,它有助于控制Http和Tcp客户端的行为。通过SpringCloud的封装,可以让我们轻松的将面向服务的REST模板请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个SpringCloud构建的微服务和基础设施中。

客户端负载均衡和服务端负载均衡的区别?

TODO: 最大的区别就是服务清单存储的位置,

  • 服务端负载均衡

image-20210517151757123

2. Ribbon的使用

  1. 通过Spring Cloud Ribbon的封装,在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:

    • 服务提供者只需要启动多个服务实例并注册到服务注册中心

    • 服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用

  2. 具体布步骤如下:

    1. 在服务消费者微服务的POM文件中添加ribbon的依赖

      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.8.RELEASE</version>
      </dependency>

      在spring cloud Eureka依赖中已经包含了spring cloud ribbon,因此无需再次引入。如过已经添加了的spring cloud Eureka依赖,不要添加该依赖,否则会遇到空指针错误。

    2. 服务提供者微服务中给RestTemplate添加@LoadBalanced注解

      @Bean
          @LoadBalanced
          public RestTemplate restTemplate()
          {
              return new RestTemplate();
          }

      image-20210517160434607

    3. 对服务消费者的controller代码进行修改

       @Autowired
          private RestTemplate restTemplate;
      ​
          @Autowired
          private LoadBalancerClient loadBalancerClient;
      ​
          @GetMapping("/user/{id}")
          public User findById(@PathVariable long id)
          {
              //hardCode硬编码方式不可取
             //return restTemplate.getForObject("http://localhost:8000/" + id,User.class);
      //修改成通过微服务的虚拟主机名来访问
              return restTemplate.getForObject("http://userservice/"+id,User.class);
          }
      ​
          @GetMapping("/log-user-instance")
          public void logUserInstances()
          {
              ServiceInstance serviceInstance = loadBalancerClient.choose("userservice");
              log.info("serviceId-->{},Host-->{},port-->{}",serviceInstance.getServiceId(),serviceInstance.getHost(),serviceInstance.getPort());
          }

      新增加了一个API接口,服务消费者访问该接口时打印出IP地址和端口号

      image-20210517160749653

    4. 现在分别启动1个服务注册中和2个服务提供者、1个服务消费者

      • 服务注册中心

        image-20210517161222111

         

      • 服务提供者

        image-20210517161324308

        这里提供一下如何在idea中如何启动两个不同端口号的服务提供者的实例

        • 在服务提供者的配置文件中已经配置了server.port=8000,因此第一个实例直接点击运行就可以咯

          image-20210517162309499

        • 选择Idea右上角启动按钮边上的Edit Configurations,在打开的对话框中,选择UserServiceApplication-->点击复制按钮->VM Options中增加-Dserver.port=8001,Apply应用,如图:

          image-20210517162438058

          最后点击运行就可以运行port=8001的实例咯

      • 服务消费者

        启动服务消费者,然后不断的访问API接口地址http://localhost:8081/log-user-instance,发现交替打印服务消费者的ip地址。

        image-20210517163043521

搭建过程中遇到的问题:

添加该依赖后,运行时报空指针错误,去掉该依赖后能正常访问。image-20210517175714002

报错信息如下:

image-20210517175601096

出现该问题的根本原因是Spring Cloud 2020.0.0版本以后对Spring Cloud NetFlix 组件进行剔除,仅保留了Eureka组件,其核心组件 Hystrix、Ribbon、Zuul、Archaius 等均进入维护状态


旧版本的spring-cloud-netflix-dependencies管理着Netflix所有组件,包括Hystrix、Ribbon、Zuul、Eureka等。而自2020.0版本起,它有且只管理Eureka(包括Server和Client)
其中Feign虽然最初属Netflix公司,但从9.x版本开始就移交给OpenFeign组织管理了,因此不再划入Netflix管辖范畴。

简单一句话概括:Spring Cloud 2020.0.0版本彻底删除掉了Netflix除Eureka外的所有组件

image-20210518111000347

Spring Cloud 既然把 Netflix 套件大刀阔斧的砍掉了,那总归得有替代方案吧。那是必然的,Spring Cloud 团队给我们推荐了用于替代的组件:

image-20210518110911185

image-20210518112004676

Spring Cloud LoadBalancer 目前仅支持轮询负载均衡策略,相对于 Ribbon 多种高可用策略还是过于简单。

3. Ribbon负载均衡策略

很多场景下,可能根据需要自定义Ribbon的配置,例如修改Ribbon的负载均衡规则等。

方法一和二适合于Spring Cloud 2020.0.0版本之前的版本,方法三适合Spring Cloud 2020.0.0版之后的Spring Cloud版本

方法一:配置文件的方式

在application.propertites文件中添加如下代码:

#更改负载均衡的负载策略
userservice.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

image-20210517223443589

方法二:使用Java代码自定义Ribbon配置

使用Ribbon提供的负载均衡策略很简单

  • 创建具有负载均衡功能的RestTemplate实例

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    使用RestTemplate进行rest操作的时候,会自动使用负载均衡策略,它内部会在RestTemplate中加入LoadBalancerInterceptor这个拦截器,这个拦截器的作用就是使用负载均衡。

  • 默认情况下会采用轮询策略,如果希望采用其它策略,则指定IRule实现,如:

    @Bean
    public IRule ribbonRule() {
        return new BestAvailableRule();
    }

方法三:负载均衡策略配置(适用于Spring Cloud 2020.0.0版之后的版本

spring cloud加入了一个新模块Spring-Loadbalancer来替代ribbon,有两种负载均衡模式(轮询和随机),默认是用轮询,假如想使用随机或者自定义负载均衡策略,就不能按照以前使用ribbon的模式(注入IRule类,必须引入ribbon依赖),那么如果我使用Loadbalancer的随机负载均衡,要怎么设置呢?官网给出比较详细的方法

显然官方写了一个切换成随机负载均衡的例子,我们拷贝过来即可。

image-20210518112950963

@Bean
        ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                                LoadBalancerClientFactory loadBalancerClientFactory) {
            String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
            return new RandomLoadBalancer(loadBalancerClientFactory
                    .getLazyProvider(name, ServiceInstanceListSupplier.class),
                    name);
​
  • 搭建步骤

    1. 把官方的@Bean方法拷贝到自己的配置类(这个类可以放到主启动类所在包及子包下,这一点和Ribbon不同

      image-20210518114000731

    2. 在启动类,使用@LoadBalancerClient或者@LoadBalancerClients注解,加载自己的配置类,由此切换loadBalancer默认的负载均衡策略

      image-20210518114034152

    3. 然后运行代码发现就切换成随机负载均衡策略咯

image-20210518113209128

4. Ribbon自定义负载均衡策略

可以参考这篇博客: https://blog.csdn.net/qq_35799668/article/details/114534023

 

 

 

原文地址:https://www.cnblogs.com/seanRay/p/14781110.html