Spring Cloud Eureka— Eureka详解

前情提要:Eureka服务治理体系中的三个核心角色:服务注册中心、服务提供者和服务消费者。
引入原因:在实践中,系统结构非常复杂,简单的服务治理内容将无法满足需求。所以需要根据实际情况做一些配置、调整和扩展。

基础架构

Eureka服务治理架构的三个核心要素:
  • 服务注册中心:Eureka提供的服务端,提供服务注册与发现功能,如前面的eureka-server。
  • 服务提供者:提供服务的应用,可以是Spring Boot应用,也可以是其他技术平台且遵循Eureka通信机制的应用。将自己的服务注册到Eureka,以供其他应用发现,如前面的hello-service。
  • 服务消费者:从服务注册中心获取服务列表,从而使消费者可以知道去何处调用其所需的服务,可以使用Ribbon或Feign来实现服务消费,如前面的ribbon-service。

    服务治理机制

    了解Eureka基础架构中各个元素的一些通信行为,以此理解基于Eureka实现的服务治理体系是如何运作起来的。如图:
  • “服务注册中心-1”和“服务注册中心-2”,它们相互注册组成了高可用集群。
  • “服务提供者”启动两个实例,一个注册到“服务注册中心-1”上,一个注册到“服务注册中心-2”上。
  • 两个“服务消费者”都分别指向一个注册中心。

    服务提供者

    服务注册

    “服务提供者” 在启动的时候会通过发送REST请求的方式将自己注册到Eureka Server 上,同时带上了自身服务的一些元数据信息。Eureka Server 接收到这个REST请求后,将元数据信息存储在一个双层结构Map中,其中第一层的key是服务名,第二层的key 是具体服务的实例名。
    在服务注册时,需要确认eureka.client.register-with-eureka=true参数是否正确,若为false,将不会启动注册操作。

    服务同步

    如上图所示,这里的两个服务提供者分别注册到了两个不同的服务注册中心上,即它们的信息分别被两个服务注册中心维护。由于服务注册中心之间为互相注册,当服务提供者发送注册请求到一个服务注册中心时,它会将请求转发给集群中相连的其他注册中心,从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两个服务注册中心中的任意一台获取到。

    服务续约

      在注册完服务之后,服务提供者会维护一个心跳用来持续告诉 Eureka Server :“我还活着”,以防止 Eureka Server 的 “剔除任务” 将该服务实例从服务列表中排除出去,我们称该操作为服务续约(Renew)。
    1
    2
    3
    4
    eureka:
    instance:
    leaseRenewalIntervalInSeconds: 30 # 续约更新时间间隔(默认为30秒)
    leaseExpirationDurationInSeconds: 90 #续约到期时间(默认90秒)

服务消费者

获取服务

到此,在服务注册中心已经注册了一个服务,并且该服务有两个实例。当我们启动服务消费者时,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server 会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新一次。

获取服务是服务消费者的基础,所以要确保 eureka-client-fetch-registery=true 参数没有被修改成false,
该值默认为 true。若想修改缓存清单的更新时间,可以通过eureka-client.registry-fetch-interval-seconds=30 参数来进行修改,该值默认为30,单位为秒。

服务调用

服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体需要调用的实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

服务下线

在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭期间,我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中,当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给 Eureka Server,告诉服务注册中心:“我要下线了”。服务端在接收到请求之后,将该服务状态设置为下线(DOWN),并把该下线事件传播出去。

服务注册中心

失效剔除

当一些外部原因如内存溢出、网络故障等导致服务实例非正常下线,而服务注册中心并未收到“服务下线”的请求。为了从服务列表中将这些无法提供服务的实例剔除,Eureka Server 在启动的时候会创建一个定时任务,默认每隔一段时间eureka.server.eviction-interval-timer-in-ms(默认60秒)将当前清单中超时(默认90秒)没有续约的服务剔除出去。

自我保护

当我们在本地调试基于 Eureka 的程序时,基本上都会在服务注册中心的信息面板上出现类似下面的红色警告信息:

实际上,该警告就是触发了Eureka Server的自我保护机制。根据前面介绍,服务注册到Eureka Server之后,会维护一个心跳连接,告诉Eureka Server 自己还活着。Eureka Server 在运行期间,会统计心跳失败的比例在15分钟之内低于85%,如果出现低于的情况,Eureka Server 会将当前的实例信息保护起来,让这些实例不会过期,尽可能保护这些注册信息。但是,在保护期间内实例若出现问题,那么客户端很容易拿到实际已经不存在的服务实例,会出现调用失败的情况,所以客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。
由于在本地调试很容易触发注册中心的保护机制,使得注册中心维护的服务实例不那么准确。可以在本地进行开发时,使用 eureka-server.enable-self-preservation=false 参数来关闭保护机制,确保注册中心将不可用的实例正确剔除。