SpringCloud:Eureka注册器,Ribbon负载均衡

240 阅读8分钟

SpringCloud 微服务

本文全程都是 qa 格式!

本文全程都是 qa 格式!

本文全程都是 qa 格式!




Eureka 注册中心

硬编码服务调用会出现什么问题

  • 消费者不知如何获取服务提供者地址信息
  • 多个提供者不知如何选择
  • 无法了解提供者健康状态

Eureka 架构中微服务分为哪两类

  • EurekaServer 服务端,注册中心
  • EurekaClient 客户端

EurekaServer EurekaClient 关系

  • image-20220516235218172

EurakaServer 有什么作用

  • 记录每个微服务的服务信息,如访问功能的接口路径。
  • 心跳监控,监控提供者微服务的健康状态。

EurekaClient 微服务分类和作用是什么

  • EurakeClient 微服务分为消费者和提供者。
  • 提供者
    • 提供者会注册自己的信息到 EurekaServer (将自己的服务信息给 EurekaServer
    • 提供者会每个30秒向EurekaServer发送心跳(想 EurekaServer 发送自己健康状态),不发送视为心跳不正常,信息会被剔除
  • 消费者
    • 消费者会根据服务名称从EurekaServer中拉去服务列表
    • 获取服务列表后做负载均衡,选中一个微服务后发起远程调用。

消费者如何获取服务提供者的具体信息

  • 服务提供者在启动时会像 Eureka 注册自己的信息。Eureka 保存这些信息。消费者根据服务名称像 Eureka 拉去提供者信息。

如果多个服务提供者,消费者如何选择

  • 消费者利用负载均衡算法,从服务列表中挑选一个

消费者如何感知提供者的健康状态

  • 提供者每隔30秒像 EurekaServer 发送心跳请求,报告健康状态。Eureka 会跟新服务列表信息,心跳不正常会被剔除。消费者就可以拉取到最新的信息。

如何搭建Eureka服务端(EurekaServer

  • 导入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    
  • 配置 Eureka

    端口、服务名称、地址信息可以根据自己的实际需求去进行修改

    server:
      # 注册端口是因为 eureka 自己也是微服务
      port: 10086
    
    # 这里是作为 eureka 微服务的注册,为了以后多个 eureka 微服务能互相通信
    spring:
      application:
        # 配置的是 eureka的服务名称
        name: eureka-server
    eureka:
      client:
        service-url:
          # 配置的是 eureka 的地址信息
          defaultZone: http://127.0.0.1:10086/eureka
    
  • 开启Eureka微服务

    在引导类上添加注解@EnableEurekaServer

    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServer {
        public static void main(String[] args) {
            SpringApplication.run(EnableEurekaServer.class, args);
        }
    
    }
    
  • 通过配置的地址跳转到对应的页面说明成功

    image-20220516233931679

EurekaServer 初始化会注册自己吗

  • 会的,EurekaServer 会注册自己。

    从下图可以看出,在初始话的时候会把自己注册到Eureka当中。

    image-20220516234357358

如何创建 Eureka 客户端(EurekaClient

  • 引入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  • 设置配置

    # 这里是作为 eureka-client 的注册
    spring:
      application:
        # 配置的是 eureka的服务名称
        name: userService
    eureka:
      client:
        service-url:
          # 根据 url 注册到对应的 EurekaServer
          defaultZone: http://127.0.0.1:10086/eureka
    
  • 当我们在EurekaServe服务端看到对应的名称的服务已经完成注册即完成

    image-20220517110500467

提供者和消费者在 Eureka 中担任什么角色

  • 提供者和消费者在 Eureka 中都是 EurekaClient,都是属于客户端。
  • 只有 EurekaServer 是客户端,用来注册和监控以及查询的作用。

idea 一个服务如何启动多个实例

Eureka 如何体现服务队列

  • 通过服务名称来区分服务队列。image-20220517164921961

若干个相同服务名称不同功能的客户端服务在同一个服务端会怎么样

  • 他们会因为服务名称相同所以在同一个服务端以服务队列的形式体现。

  • 我们从此得出一个结论,服务队列的分配依据之一是根据客户端的服务名称来完成。

    image-20220517111820302

什么是服务的发现

  • 服务的发现也可以被称为服务的拉取,是消费者向 EurekaServer 拉去对应服务名称的提供者的信息。

如何实现服务的发现

  • url ip路径换为要拉取的提供者者的服务名称。

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2. 利用 RestTemplate 发送 http 请求到对应的 微服务中
        String url = "http://user-service/user/" + order.getUserId();
        User user = restTemplate.getForObject(url, User.class);
        // 3. 封装 User 到 Order 中。
        order.setUser(user);
        // 4.返回
        return order;
    }
    

    image-20220517170656085

    image-20220517170739843

  • RestTemplate类上添加负载均衡注解@LoadBalanced

    /**
     * 创建 RestTemplate 并注入 spring 容器。
     * @return RestTemplate
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
  • 这样子就可以实现服务的发现。默认的负载均衡是两个提供者服务器轮询服务。

总结 Eureka 总体流程

  • 搭建 Eureka Server

    • 引入 eureka-server 依赖

      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>
      
    • 添加 @EnableEurekaServer注解

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

      image-20220517171553932

    • 在配置文件中配置 eureka 地址

      # 这里是作为 eurekaServer 微服务的注册,为了以后多个 eureka 微服务能互相通信
      spring:
        application:
          # 配置的是 eureka的服务名称
          name: eureka-server
      eureka:
        client:
          service-url:
            # 配置的是 eureka 的地址信息
            defaultZone: http://127.0.0.1:10086/eureka
      
  • 服务注册

    • 引入 eureka-client 依赖

      <!--Eureka客户端-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
      
    • 在配置文件中配置服务名称和 eureka 服务器地址

      # 配置服务名称
      spring:
        application:
          name: order-service
      # 配置 eureka 服务器地址    
      eureka:
        client:
          service-url:
            # 根据 url 注册到对应的 EurekaServer
            defaultZone: http://127.0.0.1:10086/eureka
      
  • 服务发现

    • 在提供者和消费者都已注册

    • 消费者通过服务提供者的服务名称远程调用

      通过 url 调用restTemplate.getForObject方法去远程调用

      public Order queryOrderById(Long orderId) {
          // 1.查询订单
          Order order = orderMapper.findById(orderId);
          // 2. 利用 RestTemplate 发送 http 请求到对应的 微服务中
          String url = "http://user-service/user/" + order.getUserId();
          User user = restTemplate.getForObject(url, User.class);
          // 3. 封装 User 到 Order 中。
          order.setUser(user);
          // 4.返回
          return order;
      }
      

      image-20220517171924997

    • RestTemplate类上添加负载均衡注解@LoadBalanced

      /**
       * 创建 RestTemplate 并注入 spring 容器。
       * @return RestTemplate
       */
      @Bean
      @LoadBalanced
      public RestTemplate restTemplate() {
          return new RestTemplate();
      }
      

Ribbon 负载均衡

负载均衡在微服务中起到了什么作用

  • 为消费者向注册器拉去提供者信息并根据负载均衡算法选择一个进行远程调用

    image-20220517175023642

负载均衡如何在微服务里面实现

  • 这是详解图,下面就让我们一起来看看如何实现

    image-20220517202825171

  1. 首先 LoadBalancerInterceptor类获取到消费者传入的uri,通过 uri获取到提供者的服务名称。将服务名称传入RibbonLoadBalancerClient类当中。

    image-20220517211040571

  2. RibbonLoadBalancerClient类获取到了服务名称,便向 Eureka注册器拉取对应提供者的服务列表,然后通过getServer传入ZoneAwareLoadBalancer类中。

    image-20220517205018391

    image-20220517200551151

  3. ZoneAwareLoadBalancer获取到服务列表之后,将其传至BaseLoadBalancer类中进行负载均衡选择。

    image-20220517205208152

  4. BaseLoadBalancer类中通过 IRule类型的 rule选择了对应的负载均衡规则并返回。

    image-20220517205556787

    image-20220517202357694

  5. 最后返回到LoadBalancerInterceptor类,修改url,拿到真实的ip地址和端口号来代替原来的服务名称,并对提供者发起请求。

负载均衡的常用策略有哪些

  • image-20220517212609386

如何自定义负载均衡的策略

  • 通过代码的方式进行调整

    通过配置类设置全局的负载均衡规则

    @Bean
    public IRule iRule() {
        // 根据自己的实际选择返回对应的负载均衡策略
        return new RoundRobinRule();
    }
    
  • 通过配置文件的方式进行调整

    通过配置文件设置单一服务的负载均衡规则

    # 服务名称
    userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 
    

代码实现和配置文件实现的自定义负载均衡策略有什么区别

  • 代码实现的负载均衡策略作用域是全体服务,即消费者调用任何服务
  • 代码方式配置灵活,但修改时需要重新打包发布
  • 配置文件的负载均衡策略作用域是指定服务,指消费者调用特定服务
  • 配置方式直观方便,无需重新打包发布,但是无法做到全局配置
  • 当两者共存的时候,必定会有冲突。所有的策略都是按照代码实现的负载均衡策略来实现。

Ribbon负载均衡的默认加载机制是什么

  • Ribbon默认的加载机制是懒加载,即当服务第一次访问的时候才会去创建LoadBalanceClient,请求时间长。

什么是饥饿加载

  • 饥饿加载不同于Ribbon默认的懒加载。当服务启动的时候便会去创建LoadBalanceClient,缩短第一次请求时间,但是增加设备负担。

如何开启饥饿加载

  • 通过配置配置文件开启指定服务名称的饥饿加载

    ribbon:
      eager-load:
        enabled: true # 开启饥饿加载
        clients:
          - userservice # 指定服务名称,这是个服务名称列表