Eureka

1 注册中心的主要作用

服务注册中心(也称注册中心)是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者

的一个作用。注册中心-般包含如下几个功能:

1.1.服务发现:

·服务注册/反注册:保存服务提供者和服务调用者的信息
·服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能
·服务路由(可选) :具有筛选整合服务提供者的能力。

1.2.服务配置:

·配置订阅:服务提供者和服务调用者订阅微服务相关的配置

·配置下发:主动将配置推送给服务提供者和服务调用者 

1.3.服务健康检测

·P检测服务提供者的健康情况

2 常见的注册中心

2.1 Zokeeper
zookeeper它是一个分布式服务框架,是Apache Hadoop的一个子项目,它主要是用来解决分布式应
用中经常遇到的一些数据管理问题,如:统-命名服务、状态同步服务、集群管理、分布式应用配置项
的管理等。简单来说zookeeper=文件系统+监听通知机制。
2.2 Eureka
Eureka是在Java语言上,基于Restful Api开发的服务注册与发现组件, Springcloud Netflix中的重要组

2.3 Consul
Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册服务软件,
采用Raft算法保证服务的一致性,且支持健康检查。

2.4 Nacos

Nacos是一个更易 于构建云原生应用的动态服务发现、配置管理和服务管理平台。简单来说Nacos就是

注册中心+配置中心的组合,提供简单易用的特性集,帮助我们解决微服务开发必会涉及到的服务注册

与发现,服务配置,服务管理等问题。Nacos 还是Spring Cloud Alibaba组件之一,负责 服务注册与

发现。

最后我们通过一张表格大致了解Eureka、Consul. Zookeeper的异同点。选择什么类型的服务注册与

发现组件可以根据自身项目要求决定。

3.EUREKA概述

3.1 eureka基础知识

Eureka是Netflix开发的服务发现框架, SpringCloud将它集成在自己的子项目spring-cloud-netflix中,

实现SpringCloud的服务发现功能。

上图简要描述了Eureka的基本架构,由3个角色组成:

3.1.1、Eureka Server

·提供服务注册和发现

3.1.2、Service Provider

·服务提供方

·将自身服务注册到Eureka ,从而使服务消费方能够找到

3.1.3、Service Consumer

·服务消费方

·从Eureka获取注册服务列表,从而能够消费服务

3.2 Eureka的交互流程与原理

4 使用eureka的步骤

4.1.搭建eureka server

4.1.1 创建工程

4.1.1 导入依赖



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    
    org.example
    euraka-server
    1.0-SNAPSHOT

    
        1.8
        Greenwich.SR2
    

    
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server
        
    

    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
    


4.1.1 修改配置文件

server:
  port: 9000
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false #是否将自己注册到eureka
    fetch-registry: false #是否从eureka获取注册信息
    service-url: #配置暴露给eureka-client请求的地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

4.1.1 配置启动类

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

4.2.将服务提供者注册到eurekaServer上

4.2.1 引入euraka-client

     
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

4.2.2 修改配置文件,添加eureka-server的信息

#配置eureka-server信息
eureka:
  client:
    service-url:
      defaulrZone: http://localhost:9000/euraka/
  instance:
    prefer-ip-address: true #使用ip地址注册

4.2.3 修改启动类,添加服务发现的支持(可选)

@SpringBootApplication
@EntityScan(value = "com.jpa.product.entity")
//开启注册
//@EnableEurekaClient
@EnableDiscoveryClient
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class,args);
    }
}

4.3.服务消费者通过注册中心获取服务列表,并调用

eureka的元数据:服务的主机名,ip等信息,可以通过eureka-server来获取,用于服务之间的相互调用

4.3.1 引入euraka-client

     
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

4.3.2 修改配置文件,添加eureka-server的信息

#配置eureka-server信息
eureka:
  client:
    service-url:
      defaulrZone: http://localhost:9000/euraka/
  instance:
    prefer-ip-address: true #使用ip地址注册

4.3.3 修改启动类,添加服务发现的支持(可选)

@SpringBootApplication
@EntityScan(value = "com.jpa.product.entity")
//开启注册
//@EnableEurekaClient
@EnableDiscoveryClient
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class,args);
    }
}

5 eureka服务的高可用集群

在上面,实现了单节点的Eureka Server的服务注册与服务发现功能。Eureka Client会定时连接 Eureka Server ,获取注册表中的信息并缓存到本地。微服务在消费远程API时总是使用本地缓存中的数 据。因此一般来说,即使Eureka Server发生宕机,也不会影响到服务之间的调用。但如果Eureka Server宕机时,某些微服务也出现了不可用的情况, Eureka Server中的缓存若不被刷新,就可能会影 响到微服务的调用,甚至影响到整个应用系统的高可用。因此,在生成环境中,通常会部署-个高可用 的Eureka Server集群。 Eureka Server可以通过运行多个实例并相互注册的方式实现高可用部署, Eureka Server实例会彼此增 量地同步信息,从而确保所有节点数据一致。事实上,节点之间相互注册是Eureka Server的默认行

为。

5.1 准备3个eureka-server的yml文件

5.1.1 主配置文件

spring:
  application:
    name: eureka
  profiles:
    active: server1

5.1.2 eureka1的配置文件

server:
  port: 8001
eureka:
  instance:
    hostname: server1
  client:
    # 表示是否注册自身到eureka服务器
    # register-with-eureka: false
    # 是否从eureka上获取注册信息
    # fetch-registry: false
    service-url:
      defaultZone: http://eureka1:8002/eureka/

5.1.3 eureka2的配置文件

server:
  port: 8002
eureka:
  instance:
    hostname: server2
  client:
    # 表示是否注册自身到eureka服务器
    # register-with-eureka: false
    # 是否从eureka上获取注册信息
    # fetch-registry: false
    service-url:
      defaultZone: http://eureka2:8001/eureka/

5.1.4 修改主机hosts文件

127.0.0.1 eureka1
127.0.0.1 eureka2

5.1.5 分别运行两次项目(指定配置文件)

5.1.6 最终效果

6 eureka常见的问题

6.1 自我保护机制

现象:页面出现如下错误“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.”,如下图

6.2、自我保护模式介绍

参考官网: https://github.com/Netflix/eureka/wiki/Understanding-Eureka-Peer-to-Peer-Communication

保护模式,是 Eureka 提供的一个特性,在默认的情况下,这个属性是打开的,而且也建议线上都使用这个特性。 如果 Eureka Server在一定时间内没有接收到某个微服务实例的心跳, Eureka Server将会注销该实例(默认 90秒) 。但是当网络分区故障发生时, 微服务与 Eureka Server之间无法正常通信,此时会触发Eureka Server进入保护模式,进入自我保护模式后,将会保护服务注册表中的信息,不再删除服务注册表中的数据。

6. 3、关于上面的问题

在上面测试过程中,只有一个Eureka Client,当这个Eureka Client服务注册后,又被关停了,就导致Eureka Client进入了保护模式。所以上面警告信息是Eureka Server进入自我保护模式之后的显示的。

6.4、相关属性设置

对于自我保护模式属性,建议都是使用默认的配置,不需要要设置这些属性。

(1)Eureka Server端

默认情况下自我保护机制是打开的,线上建议都是打开的,即不需要设置。如果在测试环境需要设置为关闭,可以通过如下配置:

# 设为false,关闭自我保护。默认是打开的。
eureka.server.enable-self-preservation=false

设置清零失效服务的间隔时间,但是不建议更改

# 清理间隔(单位毫秒,默认是60*1000)
eureka.server.eviction-interval-timer-in-ms=4000

这个“eureka.server.eviction-interval-timer-in-ms”时间,是Eureka Server执行清理无效服务的时间间隔,执行新清理任务时,如果下面判断生效,则清除服务。

当前时间 - 上次心跳时间 > lease-expiration-duration-in-seconds

其中,lease-expiration-duration-in-seconds 属性在客户端进行配置

这里一个规范就是: 服务端的“eureka.server.eviction-interval-timer-in-ms”  值  要比 客户端配置 “lease-expiration-duration-in-seconds ”的时间短。

(2) Eureka Client端

开启健康检查,默认是开启的,如下

eureka.client.healthcheck.enabled=true

心跳相关的设置

# 单位是秒,默认30秒。此客户端发送心跳的频率
eureka.instance.lease-renewal-interval-in-seconds=30
 
# 单位是秒,默认90秒,表示eureka server在收到此client上次心跳之后,间隔多久没有收到,就摘除此服务。
eureka.instance.lease-expiration-duration-in-seconds=10

控制台显示ip地址配置

#向注册中心注册服务id
instance-id: ${spring.cloud.client.ip-address}:${server.port} 

7 源码分析

7.1 回忆Eureka的一些概念:

在Eureka的服务治理中,会涉及到下面一些概念: 

服务注册: Eureka Client会通过发送REST请求的方式向Eureka Server注册自己的服务,提供自身的元数据,比如ip地址、端口、运行状况指标的url、主页地址等信息。Eureka Server接收到注册请求后,就会把这些元数据信息存储在一个双层的Map中。 

服务续约: 在服务注册后,Eureka Client会维护一个心跳来持续通知Eureka Server,说明服务一直处于可用状态,防止被剔除。Eureka Client在默认的情况下会每隔30秒发送一次心跳来进行服务续约。 

服务同步: Eureka Server之间会互相进行注册,构建Eureka Server集群,不同Eureka Server之间会进行服务同步,用来保证服务信息的一致性。 

获取服务: 服务消费者(Eureka Client)在启动的时候,会发送一个REST请求给Eureka Server,获取上面注册的服务清单,并且缓存在Eureka Client本地,默认缓存30秒。同时,为了性能考虑,Eureka Server也会维护一份只读的服务清单缓存,该缓存每隔30秒更新一次。 

服务调用: 服务消费者在获取到服务清单后,就可以根据清单中的服务列表信息,查找到其他服务的地址,从而进行远程调用。Eureka有Region和Zone的概念,一个Region可以包含多个Zone,在进行服务调用时,优先访问处于同一个Zone中的服务提供者。 

服务下线 当Eureka Client需要关闭或重启时,就不希望在这个时间段内再有请求进来,所以,就需要提前先发送REST请求给Eureka Server,告诉Eureka Server自己要下线了,Eureka Server在收到请求后,就会把该服务状态置为下线(DOWN),并把该下线事件传播出去。 

服务剔除: 有时候,服务实例可能会因为网络故障等原因导致不能提供服务,而此时该实例也没有发送请求给Eureka Server来进行服务下线,所以,还需要有服务剔除的机制。Eureka Server在启动的时候会创建一个定时任务,每隔一段时间(默认60秒),从当前服务清单中把超时没有续约(默认90秒)的服务剔除。 

自我保护: 既然Eureka Server会定时剔除超时没有续约的服务,那就有可能出现一种场景,网络一段时间内发生了异常,所有的服务都没能够进行续约,Eureka Server就把所有的服务都剔除了,这样显然不太合理。所以,就有了自我保护机制,当短时间内,统计续约失败的比例,如果达到一定阈值,则会触发自我保护的机制,在该机制下,Eureka Server不会剔除任何的微服务,等到正常后,再退出自我保护机制。

从这些概念中,就可以知道大体的流程, Eureka Client向Eureka Server注册,并且维护心跳来进行续约,如果长时间不续约,就会被剔除。 Eureka Server之间进行数据同步来形成集群,Eureka Client从Eureka Server获取服务列表,用来进行服务调用,Eureka Client服务重启前调用Eureka Server的接口进行下线操作。

7.2 spring boot 的自动装载

( 1 ) InfportSelector

ImportSelector接口是Spring导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功 能性注解)中起到了决定性的作用。当在@Configuration标注的Class 上使用@lmport引入了一个 ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean。

pub1ic interface Importselector {
String[] select Imports (Annotati onMetadata var1);

DeferredlmportSelector接口继承ImportSelector,他和ImportSelector的区别在于装载bean的时机
上,DeferredlmportSelector需要等所有的@Configuration都执行完毕后才会进行装载

public interface DeferredImportselector extends Importselector {
//...省略

7.3 eureka源码

7.3.1 分析eureka-server

1,查看需要加载的配置类

2,查看需要加载的配置类

3,查看EurekaServerAutoConfiguration类

4,查看EurekaController类

以上源码完成了eureka页面的控制

在core包下提供了eureka-client调用的方法

7.3.2 分析eureka-client源码

最终由DiscoveryClient类中的register方法调用register方法请求注册接口进行注册

详细源码分析请查看: https://blog.csdn.net/chayangdz/article/details/82012937

入门项目地址: https://gitee.com/aliuputin/spring_cloud_demo