Eureka服务注册与发现

介绍

又称服务中心,管理各种服务功能包括服务的注册、发现、熔断、负载、降级等。

任何一个服务都不能直接去掉用,都需要通过注册中心来调用。通过服务中心来获取服务你不需要关注你调用的项目IP地址,由几台服务器组成,每次直接去服务中心获取可以使用的服务去调用既可。

由于各种服务都注册到了服务中心,就有了很多高级功能条件。比如几台服务提供相同服务来做客户端负载均衡(Ribbon);监控服务器调用成功率来做断路器(Hystrix),移除服务列表中的故障点;监控服务调用时间来对不同的服务器设置不同的权重、智能路有(Zuul)等等。

Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现。Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server,并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。Spring Cloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。

Eureka的两个组件

Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。

单机版Eureka

  1. 创建module(cloud-eureka-server7001)

  2. 引入pom依赖

    在父工程中:

        <dependencies>
            <!--eureka-server-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
            <dependency>
               <!--公共模块--> 
                <groupId>org.example</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>${project.version}</version>
            </dependency>
            <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>
            <!--一般为通用配置-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    
    </project>
    

    在你要使用Eureka的服务模块中的pom加入

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

3.在application.yml 中进行Eureka配置

server:
  port: 7001

eureka:
  instance:
    hostname: localhost #eureka服务端的实例名称
  client:
    register-with-eureka: false #false表示不向注册中心注册自己
    fetch-registry: false #false 表示自己端就是祖册中心,我的职责就是维护服务实例,并不是去检索服务
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/  #设置与Eureka Service交互的地址查询服务和注册服务都需要依赖这个地址

4.在springboot启动类里面使用@EnableEurekaServer来开启 Eureka Server

@SpringBootApplication
@EnableEurekaServer//开启Eureka Server
public class ServerMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(ServerMain7001.class,args);
    }
}

5.启动module 访问 http://localhost:7001 会出现以下页面.

image-20200320143836318

微服务入驻Eureka Server

  • 引入依赖

    <!--  eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  • application.yaml中配置

    eureka:
      client:
        register-with-eureka: true #表示见自己的服务注册到Eureka Server 中 ,默认为true
        fetch-registry: true #是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        service-url:
          defaultZone: http://localhost:7001/eureka
    
    
  • 开启 Eureka client

    @SpringBootApplication
    @EnableEurekaClient//千万不要写错不要写成了EnableEurekaServer
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class, args);
        }
    }
    
  • 启动看结果 访问 http://localhost:7001/

    image-20200320150657264

    image-20200320150723540

集群版Eureka

  • 因为我们要模拟几台服务器做集群,所以我们先在 ==C:\Windows\System32\drivers\etc== 路径下的hosts文件后面加上 (你要玩几台就加几个,由于这个文件是系统文件所以需要把文件复制到桌面来修改在替换回去)

    • 127.0.0.1 cloud7001.com
    • 127.0.0.1 cloud7002.com
  • 创建一个cloud-eureka-server7002(把cloud-eureka-server7001的配置弄过来后面稍稍改下配置就好)

  • 因为 多个注册中心是:==互相注册相互守望== ,所以修改配置cloud-eureka-server7002cloud-eureka-server7001的application.yaml

    • cloud-eureka-server7001---application.yml

      server:
        port: 7001
      
      eureka:
        instance:
          hostname: eureka7001.com #eureka服务端的实例名称
        client:
          register-with-eureka: false #false表示不向注册中心注册自己
          fetch-registry: false #false 表示自己端就是祖册中心,我的职责就是维护服务实例,并不是去检索服务
          service-url:
            defaultZone: http://eureka7002.com:7002/eureka/  #设置与Eureka Service交互的地址查询服务和注册服务都需要依赖这个地址
      
    • cloud-eureka-server7002---application.yml

      server:
        port: 7002
      
      eureka:
        instance:
          hostname: eureka7002.com #eureka服务端的实例名称
        client:
          register-with-eureka: false #false表示不向注册中心注册自己
          fetch-registry: false #false 表示自己端就是祖册中心,我的职责就是维护服务实例,并不是去检索服务
          service-url:
            #集群版需要互相掉
            defaultZone: http://eureka7001.com:7001/eureka/  #设置与Eureka Service交互的地址查询服务和注册服务都需要依赖这个地址
      
  • 然后运行看下效果

    • image-20200321102056252
    • image-20200321102115781
    • 可以看到是互相依赖互相守望的

配置集群的支付服务模块

  • 创建cloud-provider-payment8002(同样我们吧cloud-provider-payment8001的配置复制过来稍稍的修改一下就好)

  • 修改配置

    • application.yml(同时修改8001-8002)

      server:
        port: 8002  #记得端口要改成对应的
      
      spring:
        application:
          name: cloud-payment-service #服务名称
      
        datasource:
          type: com.alibaba.druid.pool.DruidDataSource  #当前数据源操作类型
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://rm-bp15x4v3331c04pq86o.mysql.rds.aliyuncs.com:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false
          username: root
          password: Hzx3869327
      eureka:
        client:
          register-with-eureka: true #表示见自己的服务注册到Eureka Server 中 ,默认为true
          fetch-registry: true #是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
          service-url:
      #     defaultZone: http://localhost:7001/eureka
            defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
        instance:
          instance-id: payment8002
          prefer-ip-address: true #显示ip
      mybatis:
        mapper-locations: classpath:mapper/*.xml
        type-aliases-package: com.hzx.springcloud.entities  #所有entity别名所在包
      
  • 修改cloud-consumer-order80

    • application.yaml

      server:
        port: 80
      
      spring:
        application:
          name: cloud-consumer-service  #服务吗
      eureka:
        client:
          register-with-eureka: true #表示见自己的服务注册到Eureka Server 中 ,默认为true
          fetch-registry: true #是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
          service-url:
      #      defaultZone: http://localhost:7001/eureka  单机版
             defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      
    • controller改成

         //先暂时固定
          // private static final String PAYMENT_URL="http://localhost:8001";
      private static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";//Eureka 上对应的服务名
      
    • 主要的一点记得吧RestTemplate开启负载均衡具体:

      • 在配置RestTemplate中的Config中添加@LoadBalanced

        /**
         *LoadBalanced 负载均衡
         * @return
         */
        @Bean
        @LoadBalanced//赋予RestTmplate负载均衡的能力
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
        

Eureka自我保护机制

默认情况下,当eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是,如果短时间内丢失大量的实例心跳,便会触发eureka server的自我保护机制,比如在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews thresholdRenews(last min),当后者(最后一分钟收到的心跳数)小于前者(心跳阈值)的时候,触发保护机制,会出现红色的警告:

EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.

image-20200323131028433

官方对于自我保护机制的定义:

自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。

关闭Eureka的自我保护机制

将Eureka Server中的Application.yamlserver.enable-self-preservation设置为false

server:
  enable-self-preservation: false #将Eureka的自我保护机制设置为false就是禁用
  

为了能更快的看到效果我这里也设置一下这个

# Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
# Eureka服务端在收到最后一次心跳后等待时间上限 ,单位为秒(默认是90秒),超时剔除服务
lease-expiration-duration-in-seconds: 2

测试:

发现Eureka很贴心很明确的告诉了我们自我保护机制已经禁用了

image-20200323134917328

这是后我把服务给关了,等待1秒可以发现他立马就注销了这个服务

但是一般情况下是不会关闭这个机制的,因为这个自我保护机制对于我们来说很友好

微服务发现Discovery

对于注册进Eureka里的服务,可以通过服务发现来获得该服务的信息,也是非常的简单

具体操作步骤:

  1. 修改cloud-provider-payment8001的Controller

    @Autowired
    private DiscoveryClient discoveryClient;
    
    //以及一个方法
      @GetMapping(value = "/payment/discovery")
        @ResponseBody
        public Object Discovery(){
            List<String> services = discoveryClient.getServices();
            for (String s:services
                 ) {
                log.info("*******element"+s);
            }
            List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
            for (ServiceInstance si:instances
                 ) {
                log.info("************instances"+si.getInstanceId()+"\t"+si.getServiceId()+"\t"+si.getHost()+"\t"+si.getPort()+"\t"+si.getUri());
    
            }
            return this.discoveryClient;
        }
    
  2. 还有最重要的一步在主启动类上加@EnableDiscoveryClient注解

  3. 测试

    image-20200321145038389

    控制台成功输出了

    image-20200321145150890

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

只有不断的努力才会有更大的惊喜等着你去发现!!