一、Spring Cloud Eureka简介
Spring Cloud Eureka是Spring Cloud Netflix微服务套件中的一部分,它基于Netflix Eureka做了二次封装,主要完成微服务架构中的服务治理功能。Spring Cloud通过为Eureka增加了Spring Boot 风格的自动化配置,我们只需要通过简单的引入依赖和注解配置就能让Spring Boot构建的微服务应用轻松地与Eureka服务治理提醒进行整合。
Eureka服务端,我们也称为服务注册中心,它同其他服务注册中心一样,支持高可用配置。它依托于强一致性提供良好的服务实例可用性,可以应对多种不同的故障场景。如果Eureka以集群模式部署,当集群中有分片出现故障时,那么Eureka就转入自我保护模式。它允许在分片故障的期间继续提供服务的发现和注册,当故障分片恢复运行时集群中的其他分片会把它们的状态再次同步回来。以AWS上的实践为例,Netflix推荐每个可用的区域运行一个Eureka服务端,通过它来形成集群。不同可用区域的服务注册中心通过异步模式互相复制各自的状态,这意味着在任意给定的时间点每个实例关于所有服务的状态是有细微差别的。
Eureka客服端,主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在应用程序运行时,Eureka客户端向注册中心注册自身提供的服务并定期性的发送心跳来更新它的服务租约。同时,它也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期性的刷新服务状态。
二、Eureka服务治理体系详解
Eureka服务治理 体系主要包括三个角色:服务注册中心、服务提供者以及服务消费者。
基础架构
在Eureka整个服务治理架构中包含了三个核心要素:
服务注册中心:Eureka提供的服务端,主要提供服务注册于发现功能。
服务提供者:提供服务的应用,可以使Spring Boot应用,可以使其他技术平台且遵循Eureka通信机制应用。它将自己提供的服务注册到Eureka,以供其他 应用发现。
服务消费者:消费者应用从服务注册中心获取服务 列表,从而使消费者可以知道去何处调用其所需要的服务。
服务治理机制
![b92e24add44ada5a01092ff5f1486f6f.png](https://i-blog.csdnimg.cn/blog_migrate/ab862a8abf662a5140c70bf210fdd14d.jpeg)
通过上面图解,我们进一步了解基于Eureka的服务治理中心是如何一步步运行起来的。
首先我们先来介绍上面图中几个关键的元素:
- 服务注册 中心-1和服务注册中心-2,他们互相注册中了高可用集群。
- 服务提供者启动了两个实例,一个注册到 “服务注册中心-1”上,另一个注册到了服务注册中心-2上面。
- 还有两个服务消费者,他们也都分别指向了一个注册中心。
服务提供者
服务注册
“服务提供者”在服务启动是时候通过发送REST请求的方式将自己注册到Eureka Server上面,同时携带了 自身的一些元数据,当Eureka Server接收到REST请求以后,将数据存储在一个双层结构的Map中,其中第一层是服务名称,第二层是具体的服务实例名称。
在服务注册代码中,我们需要确认一下 eureka.client.register-with-eureka=true参数是否正确,默认配置是true,如果配置成false将不会启动注册功能
服务同步
如上图所示,两个服务提供者分别注册到不同的注册中心,也就是说,他们的信息分别被两个注册中心所维护。此时,由于注册中心之间也互相注册为服务,当服务提供者发送注册请求到一个注册中心的时候,它会将该请求转发给集群中心的其他注册中心,从而实现注册中心的服务同步。通过服务同步,两个服务提供者的信息就可以通过任意一个注册中心获得。
服务续约
当服务注册完成以后,服务提供者会维护一个心跳用来持续告诉Eureka Server:“我还活着”,以防止被Eureka的剔除任务从服务列表中剔除,我们称该操作为服务续约。
关于服务续约我们有两个重要属性,我们可以关注并根据需要进行调整:
eureka.instance.lease-renewal-interval-in-seconds=30
eureka.instance.lease-expiration-duration-in-seconds=90
eureka.instance.lease-renewal-interval-in-seconds参数用于定义服务续约任务调用间隔时间,默认为30秒。 eureka.instance.lease-expiration-duration-in-seconds参数用于定义服务失效的时间,默认为90秒。
服务消费者
获取服务
到这里,在服务注册中心已经注册了一个服务,并且该服务有两个实例。当我们 启动服务消费者的 时候,他会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server会维护一份只读服务清单来返回客户端,同时该缓存清单每隔30秒更新一次。
获取服务是服务消费者的基础,所以必须确保eureka.client.fetch-registry=true参数没有被修改成false,该值默认为true。若希望修改缓存清单的更新时间,可以 通过eureka.client.rgistry-fetch-interval-seconds=30参数进行修改,该参数默认为30,单位秒。
服务调用
服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息,因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon中或默认采用轮询的方式进行调用,从而实现客户端的负载均衡。
对于访问实例的选择,Eureka中有Region和Zone的概念,一个Region中可以包含多个Zone,每个服务客户端需要被注册到一个Zone中,所以每个客户端对应一个Region和一个Zone。在进行服务调用的时候,优先访问同处一个Zone中的服务提供方,若访问不到,就访问其他的Zone。
服务下线
在系统运行的过程中必然会面临关闭或者重启服务的某个实例的情况,在服务关闭期间,我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中,当服务实例进行正常关闭的时候,他会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线了”。服务端在接受到请求以后,将该服务状态设置为下线(DWON),并把该下线事件传播出去。
服务注册中心
有些时候,我们的服务实例并不一定会正常下线,可以由于内存溢出、网络故障等等原因使得服务不能正常工作,而服务注册中心并未收到“服务下线”请求。为了从服务列表中讲这些无法提供服务的实例剔除,Eureka Server在启动的时候会创建一个定时任务,默认每隔一段时间(默认为60s)将当前清单中超时(默认90s)没有续约的服务剔除出去。
自我保护
当我们在本地调试Eureka程序时,基本上都会遇到一个这样的问题,在服务注册中心的信息面板中出现类似下面的红色警告信息:
![68c99f3ab2ca8d8190eada9cbfa76677.png](https://i-blog.csdnimg.cn/blog_migrate/7eebcc2f0f000c035b927360f51bf7d5.jpeg)
实际上,该警告就是触发了Eureka Server的自我保护机制。之前我们介绍过,服务注册到Eureka Server之后,会维护一个心跳连接,告诉Eureka Server自己还活着。Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否 低于85%,如果出现低于的情况,Eureka Server 会将当前的实例注册信息保护起来,让这些实例不会过期,尽可能保护这些注册信息,但是,在这段保护期间内若实例出现问题, 那么客户端很容易拿到实际已经不存在的服务实例,会出现调用 失败的情况,所以 客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。
由于本地调试很容易触发Eureka Server的保护机制,这会使得注册中心维护的服务实例不那么准确。所以在本地进行开发的时候,可以使用eureka.server.enable-self-preservation=false参数来关闭自我保护机制,以确保注册中心可以将不可用的实例正确剔除。
三、代码实例
实例代码地址:https://github.com/zhenghaoxiao/spring-cloud-in-action/tree/dev