SpringCloud (一) Eureka

Eureka

  1. Eureka 是一个服务治理组件,它主要包括服务注册和服务发现,主要用来搭建服务注册中心。
  2. Eureka 是一个基于 REST 的服务,用来定位服务,进行中间层服务器的负载均衡和故障转移。
  3. Eureka Server 作为服务注册的服务端,它是服务注册中心,而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka
  4. Server 服务端,并维持心跳连接,Eureka 客户端是一个 Java 客户端,用来简化与服务器的交互、负载均衡,服务的故障切换等

Eureka 与 Zookeeper 的比较

  • Zookeeper 保证 CP(保证强一致性)
    在 ZooKeeper 中,当 master 节点因为网络故障与其他节点失去联系时,剩余节点会重新进行 leader 选举,但是问题在于,选举 leader 需要一定时间, 且选举期间整个 ZooKeeper 集群都是不可用的,这就导致在选举期间注册服务瘫痪。
    在云部署的环境下,因网络问题使得 ZooKeeper 集群失去 master 节点是大概率事件,虽然服务最终能够恢复,但是在选举时间内导致服务注册长期不可用是难以容忍的。
  • Eureka 保证 AP
    Eureka 优先保证可用性,Eureka 各个节点是平等的,某几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka 的客户端在向某个 Eureka 注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台 Eureka 还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。

配置 Eureka 服务注册中心

  1. 创建一个 SpringBoot 项目,并且添加 SpringBoot 的相关依赖;springcloud-eureka-server

  2. 添加 eureka 的依赖

    <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    
  3. 在 Spring Boot 的入口类上添加一个@EnableEurekaServer 注解,用于开启 Eureka 注册中心服务端

  4. 在 application.yml文件中配置 Eureka 服务注册中心信息:

    # 应用名称
    spring:
      application:
        name: EurekaServer
    server:
      port: 8761
    eureka:
      instance:
        hostname: localhost
      client:
        register-with-eureka: false
        fetch-registry: false
        service-url:
          defaultZone: //${eureka.instance.hostname}:${server.port}/eureka
    
  5. 启动main,访问 //localhost:8761/

Eureka 服务注册中心注册服务

  1. 新建spring boot项目并导入eureka 客户端依赖:

    <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  2. 在main上添加@EnableEurekaClient 注解

  3. 配置服务名称和注册中心地址

    spring:
      application:
        name: EurekaClient
    server:
      port: 8762
    eureka:
      client:
        register-with-eureka: true
        fetch-registry: true
        service-url:
          defaultZone: //localhost:8761/eureka
      instance:
        prefer-ip-address: true
    
  4. 启动运行之后,通过在浏览器地址栏访问我们之前搭建好的 eureka 注册

Eureka 注册中心高可用集群

由于注册中心 eureka 本身也是一个服务,如果它只有一个节点,那么它有可能发生故障,这样我们就不能注册与查询服务了,所以我们需要一个高可用的服务注册中心,这就需要通过注册中心集群来解决。

Eureka Server 的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就会形成一组互相注册的服务注册中心,进而实现服务清单的互相同步,往注册中心 A 上注册的服务,可以被复制同步到注册中心 B 上,所以从任何一台注册中心上都能查询到已经注册的服务,从而达到高可用的效果。

  1. 在 8761 的配置文件中,让它的 service-url 指向 8763,在 8763 的配置文件中让它的 service-url 指向 8761

    server:
      port: 8761
    eureka:
      instance:
        hostname: localhost
      client:
        register-with-eureka: false
        fetch-registry: false
        service-url:
          defaultZone: //${eureka.instance.hostname}:8763/eureka
    
    server:
      port: 8763
    eureka:
      instance:
        hostname: localhost
      client:
        register-with-eureka: false
        fetch-registry: false
        service-url:
          defaultZone: //${eureka.instance.hostname}:8761/eureka
    
  2. 然后在本地 hosts 文件配置:C:\Windows\System32\drivers\etc\hosts

    127.0.0.1 eureka8761

    127.0.0.1 eureka8763

  3. 分别启动两个注册中心,访问两个注册中心页面,观察注册中心页面是否正常

  4. 在eureka-client服务中配置:

    eureka:
      client:
        register-with-eureka: true
        fetch-registry: true
        service-url:
          defaultZone: //localhost:8761/eureka, //localhost:8763/eureka
    
  5. 启动服务提供者服务,然后观察注册中心页面,可以看到服务会在两个注册中心上都注册成功

Eureka 服务注册中心自我保护机制

当 Eureka 注册中心进入自我保护模式时,在 Eureka Server 首页会输出如下警告信息:

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

在没有 Eureka 自我保护的情况下,如果 Eureka Server 在一定时间内没有接收到某个微服务实例的心跳,Eureka Server 将会注销该实例,但是当发生网络分区故障时,那么微服务与 Eureka Server 之间将无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是正常的,此时不应该注销这个微服务,如果没有自我保护机制,那么 Eureka Server 就会将此服务注销掉。

Eureka 通过“自我保护模式”来解决这个问题——当 Eureka Server 节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么就会把这个微服务节点进行保护。一旦进入自我保护模式,Eureka Server 就会保护服务注册表中的信息,不删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该 Eureka Server 节点会再自动退出自我保护模式。

但是 Eureka Server 自我保护模式也会给我们带来一些困扰,如果在保护期内某个服务提供者刚好非正常下线了,此时服务消费者就会拿到一个无效的服务实例,此时会调用失败,对于这个问题需要服务消费者端具有一些容错机制,如重试,断路器等。

自我保护常用几个配置:

  1. 服务器端

    #测试时关闭自我保护机制,保证不可用服务及时踢出

    eureka.server.enable-self-preservation=false
    
  2. 客户端

    #每间隔 2s,向服务端发送一次心跳,证明自己依然”存活”

    eureka.instance.lease-renewal-interval-in-seconds=2 
    

    #告诉服务端,如果我 10s 之内没有给你发心跳,就代表我故障了,将我踢出掉

    eureka.instance.lease-expiration-duration-in-seconds=10