【三】、Eureka服务注册中心

1.什么是Eureka?

  • Eureka是Netfilix公司开源的一个服务注册与发现的组件,即服务注册中心(可以是一个集群),对外暴露自己的地址
  • Eureka和其他Netflix公司的服务组件(例如负载均衡、熔断器、网关等)一起,被SpringCloud社区整合为Spring-Cloud-Netflix模块
  • Eureka包含两个组件:Eureka Server(服务注册中心)和Eureka Client(服务消费者、服务提供者)
    • Eureka Client中的两个角色的作用
    1. 提供者:启动后向Eureka注册自己的信息(地址,提供什么服务)
    2. 消费者:向Eureka订阅服务,Eureka会将对应服务的所有提供者的地址列表发送给消费者,并且定期更新
  • 心跳(续约):提供者定期通过http方式向Eureka刷新自己的状态
  1. Eureka Server提供服务注册服务:各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
  2. Eureka Client通过注册中心进行访问:是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)

Eureka系统架构

2.Eureka客户端与服务器之间的通信

服务发现有两种模式:

  • 客户端发现模式
  • 服务端发现模式

Eureka采用的是客户端发现模式

  1. Register(注册)

    Eureka客户端将关于运行实例的信息注册到Eureka服务器,注册发生在第一次心跳。

  2. Renew(更新/续借)

    Eureka客户端需要更新最新注册信息(续借),通过每30秒发送一次心跳。更新通知是为了告诉Eureka服务器,实例仍然是存活的。如果服务器在90秒内没有看到更新,他会将实例从注册表中删除,建议不要更改更新间隔,因为服务器使用该信息来确定客户机与服务器之间的通信是否存在广泛传播的问题。

  3. Fetch Registry(抓取注册信息)

    Eureka客户端从服务器获取注册表信息并在本地缓存。之后,客户端使用这些信息来查找其他服务。通过在上一个获取周期和当前获取周期之间获取增量更新,这些信息会定期更新(每30秒更新一次)。获取的时候可能返回相同的实例。Eureka客户端自动处理重复信息。

  4. Cancel(取消)

    Eureka客户端在关机时向Eureka服务器发送一个取消请求。这将从服务器的实例注册表中删除实例,从而有效地将实例从流量中取出。

3.Eureka的自我保护机制

如果 Eureka 服务器检测到超过预期数量的注册客户端以一种不优雅的方式终止了连接,并且同时正在等待被驱逐,那么它们将进入自我保护模式。这样做是为了确保灾难性网络事件不会擦除eureka注册表数据,并将其向下传播到所有客户端。

任何客户端,如果连续3次心跳更新失败,那么它将被视为非正常终止,病句将被剔除。当超过当前注册实例15%的客户端都处于这种状态,那么自我保护将被开启。

当自我保护开启以后,eureka服务器将停止剔除所有实例,直到:

  1. 它看到的心跳续借的数量回到了预期的阈值之上
  2. 自我保护被禁用

默认情况:自我保护是启用的,并且默认的阈值是要大于当前注册数量的15%

4.Eureka服务端实现

  1. 建立cloud-eureka-server7001模块

  2. 导入相关依赖

    <dependencies>
            <!--eureka-server-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
            <!--自定义api通用包-->
            <dependency>
                <groupId>com.asule</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
            <!--boot web acctuator-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot</artifactId>
            </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>
        </dependencies>
    
  3. 在工程中新建application.yml文件

    server:
      port: 7001
    
    #eureka 配置
    #eureka 一共有四部分配置
    #1.dashboard:eureka的web控制台的配置 图形化界面的注册工具
    #2.server:eureka的服务端的配置
    #3.client:eureka的客户端的配置
    #4.instance:eureka的项目的实例
    
    
    eureka:
      instance:
        hostname: localhost #主机名
    
      client:
        #是否将自己的路径注册到eureka上。eureka server是服务端因此不需要,eureka client客户端(提供者)需要,默认值是true
        register-with-eureka: false
        #是否现需要从eureka中抓取路径。eureka server是服务端因此不需要,eureka client客户端(消费者)需要,默认值是true
        fetch-registry: false
        service-url:
          #eureka服务端地址,将来客户端使用该地址和eureka进行通信,默认也是这个值
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
    

    default默认端口是8761default默认端口

  4. 编写启动类

    需要在启动类上添加@EnableEurekaServer注解来启用EurekaServer

    package com.asule;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    /**
     * @author: ASULE
     * @create: 2022/1/23 10:03
     * @version: 1.0
     **/
    @SpringBootApplication
    //启用EurekaServer
    @EnableEurekaServer
    public class EurekaApplication7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaApplication7001.class,args);
        }
    }
    
    

4.Eureka客户端(提供者)实现

将支付微服务8001注册到7001服务中心

  1. 在8001的pom文件中添加eureka-server依赖

    <!--eureka-server-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  2. 在支付微服务8001提供者的yml文件中添加配置

    后续还要添加参数用来演示心跳

    eureka:
      instance:
        hostname: localhost #主机名
    
      client:
        #是否将自己的路径注册到eureka上。
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          #eureka服务端地址,将来客户端使用该地址和eureka进行通信,默认也是这个值
          defaultZone: http://localhost:7001/eureka/
    
  3. 在支付微服务8001启动类中添加注解,添加后的代码如下

    添加@EnableEurekaClient注解(注:不添加也是可以的,是可以省略的,但是不建议省略

    package com.asule;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentApplication8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentApplication8001.class,args);
        }
    }
    

5.Eureka客户端(消费者)实现

  1. 在80的pom文件中添加eureka-server依赖(同上)
  2. 在消费微服务80消费者的yml添加配置(同上)
  3. 在消费微服务80端口启动类加上@EnableEurekaClient注解

6.启动服务测试

  1. 开启Eureka Server端口
  2. 开启Eureka Client端口
  3. 成功服务测试

Ⅰ.原理说明

服务注册:将服务信息注册到注册中心
服务发现:从注册中心获取服务信息
实质:存key服务名,取value调用地址

Ⅱ.步骤

  1. 先启动Eureka服务注册中心
  2. 启动服务提供者payment支付服务
  3. 支付服务启动后会把自身信息注册到eureka
  4. 消费者order服务在需要调用接口时,使用服务别名取注册中心获取实际的远程调用地址
  5. 消费者获得调用地址后,底层实际是调用httpClient技术实现远程调用
  6. 消费者获得服务地址后会缓存到本地的JVM中,默认每30秒更新一次服务调用地址

Ⅲ.问题

问题:微服务RPC远程调用最核心的是什么?
答:高可用,因此如果注册中心只有一个,当这一个注册中心出现故障的时候,会导致整个服务环境不可用
解决办法:搭建eureka注册中心集群,实现负载均衡+故障容错

原理说明
集群的作用:相互注册,相互守望
集群

7.Eureka集群搭建步骤

  1. 根据7001创建7002,除了启动类和yml配置文件,其余都是一样的。

  2. 修改host文件,在C:\Windows\System32\drivers\etc下的hosts

    #springcould cloud2022
    127.0.0.1	eureka7001
    127.0.0.1	eureka7002
    
  3. 修改7001项目application.yml

    server:
      port: 7001
    
    #eureka 配置
    #eureka 一共有四部分配置
    #1.dashboard:eureka的web控制台的配置 图形化界面的注册工具
    #2.server:eureka的服务端的配置
    #3.client:eureka的客户端的配置
    #4.instance:eureka的项目的实例
    
    
    eureka:
      instance:
      ########################主机名进行了改动,当前并不是在服务器上,所以主机其实都是127.0.0.1(环回地址)即自己电脑的ip,目前只是为了便于区分#################
        hostname: eureka7001 #主机名 
    
      client:
    #为了在eureka注册中心更好的观测到集群,将自身注册到eureka上
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #单机模式
      defaultZone: http://eureka7002:7002/eureka #相互注册
      spring:
    	  application:
    	    name: eureka-server
      
    
  4. 修改7002项目的application.yml

    server:
      port: 7002
    
    
    eureka:
      instance:
        hostname: eureka7002 #主机名
    
      client:
    #为了在eureka注册中心更好的观测到集群,将自身注册到eureka上
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #单机模式
      defaultZone: http://eureka7001:7001/eureka #相互注册http://${eureka.instance.hostname}:${server.port}/eureka
      spring:
    	  application:
    	    name: eureka-server
    
  5. 在Eureka Client客户端(提供者和消费者)注册Eureka集群

    eureka:
      client:
        #可以不写,因为默认是true
        register-with-eureka: true
        #可以不写,因为默认是true
        fetch-registry: true
        service-url:
          #defaultZone: http://localhost:7001/eureka/
          defaultZone: http://eureka7001:7001/eureka,http://eureka7002:7002/eureka #集群Eureka注册
    
  6. 启动Eureka集群,在启动提供者,最后启动消费者查看效果
    集群搭建成功

8.支付服务集群搭建以及负载均衡

  1. 根据8001搭建8002服务

  2. 测试8002服务功能

    1. 测试get服务
      测试get服务
    2. 测试create服务
      测试create服务
  3. Eureka服务中心显示

    发现支付微服务集群和Eureka集群都配置好了

    两个集群

  4. 测试8001和8002的get方法都可以返回值

    访问localhost:8001/payment/get/1
    访问localhost:8002/payment/get/1

  5. 用消费者的方式访问

    在支付微服务中加入port显示当前消费者使用的哪一个微服务

    显示当前消费者端口

    访问localhost:80/consumer/payment/get/1

    发现问题: 无论怎么测试端口都是8001访问localhost:80/consumer/payment/get/1

    原因: 在消费者controller中将请求路径写死了
    路径写死了
    解决方法:
    将写死的路径更改成Eureka服务注册中心的名称
    更改成Eureka服务注册中心的名称
    又会出现一个问题:
    这个时候去访问localhost/consumer/payment/get/1会出现500错误
    500错误
    为什么?

    由于CLOUD-PAYMENT-SERVICE是支付微服务的集群,我们是配置了以服务名的方式访问,但是并不能确定是该集群中的哪一个服务

    加了服务名称后返回500错误的解决办法

    使用@LoadBalanced注解赋予RestTemplate负载均衡的能力,切记修饰在RestTemplate的Bean上

    package com.asule.config;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * @author: ASULE
     * @create: 2022/1/22 18:43
     * @version: 1.0
     **/
    @Configuration
    public class Config {
        /*
            @Bean注解:用于告诉方法,产生一个Bean对象
        ,然后把这个Bean对象交给Spring管理
            @LoadBalanced:开启负载均衡,默认是轮循
         */
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
    

9._actuator微服务信息完善

修改主机名称

在要修改的主机的yml文件中添加配置

添加的配置

#将当前实例的ip注册到eureka server中。默认的是false所以注册的是主机名
prefer-ip-address: true
#设置当前实例的ip
ip-address: 127.0.0.1
#设置web控制台显示的实例id (当前是 ip:应用名称:端口)
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}

10.服务发现Discovery

对于注册进Eureka里面的微服务可以通过服务发现Discovery来获得服务的信息

  1. 在payment8001的控制层中添加代码

     //此处引入的是cloud.client下的DiscoveryClient接口包
        @Autowired
        private DiscoveryClient discoveryClient;
    
        @GetMapping("/discovery")
        public Object discovery(){
            List<String> services = discoveryClient.getServices();
            for (String element : services) {
                log.info("******element:"+element);
            }
            //ServiceInstance是服务实例
            List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
            for (ServiceInstance instance : instances) {
                log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
            }
            return this.discoveryClient;
        }
    
  2. 在8001启动类上添加@EnableDiscoveryClient注解

    @EnableDiscoveryClient注解注解可以省略但是不建议省略
    @EnableDiscoveryClient和@EnableEurekaClient:
    共同点:都能够让注册中心能够发现,扫描到该服务。
    不同点:@EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient 可以是其他注册中心。

  3. 测试

    Eureka服务中心
    Eureka服务中心

    Java
    Java中的日志

    测试得到的值
    得到的值

11.Eureka的自我保护机制

保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务

如果再Eureka Server的首页看到了如下的提示,说明Eureka进入了保护模式

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.

一句话:某时刻某一个微服务不可用了,Eureka不会立即清理,依旧会对该微服务的信息进行保存。属于CAP中的AP分支

为什么会产生自我保护机制?
为了防止Eureka Client可以正常运行,但是与Eureka Server网络不通的情况下,Eureka Server不会理科将Eureka Client服务剔除。

什么是自我保护?
默认情况下,如果Eureka Server在一定时间内没有收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络发送(延迟、卡顿、拥挤)时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实时健康的, 因此此时不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢包过多客户端时(很有可能发生了网络分区故障),那么这个节点就会进入自我保护模式

自我保护机制

在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。

结论:自我保护模式时一种应对网络异常的安全保护措施。它的架构哲学时宁可同时保护所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka汲取更加健壮和稳定。

如何禁止自我保护机制?

先关闭8001和7001的集群配置再测试
服务提供者:

lease-renewal-interval-in-seconds: 3 #每隔3秒发一次心跳包,默认30s
lease-expiration-duration-in-seconds: 9 #如果9秒没有发心跳包,eureka-server会把这个服务干掉 默认90s

服务提供者
Eureka中显示字样则已经关闭
显示字样

注册中心配置:

  server:
    enable-self-preservation: false #关闭自我保护机制
    eviction-interval-timer-in-ms: 3000 #检测服务的时间间隔毫秒为单位

测试

  1. 先启动7001再启动8001

  2. 进入Eureka注册中心查看
    是否可以开启

  3. 关闭8001端口模拟网络异常

  4. 速度刷新Eureka注册中心

    出现No instances available则成功

    关闭自我保护成功

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值