阿里P7带你探究springCloud神秘的注册中心Eureka

一、什么是Eureka

Eureka是Netflix公司开源的产品,它是一种基于REST( Representational State Transfer )的服务,主要用于AWS云。 Eureka提供了完整的Service Registry和Service Discovery实现实现,也是Spring Cloud体系中最重要的组件之一。

简单来说Eureka就是Netflix开源的一款提供服务注册和发现的产品,并且提供了java客户端。当然,springcloud大力优化后的Eureka,可以应用在任何需要使用注册中心的场景。

Eureka由两个组件组成:Eureka服务端和Eureka客户端。Eureka服务端就是注册中心。Eureka客户端是一个java客户端,用来简化与服务端的交互、作为轮询负载均衡器,并提供服务的故障切换支持。

下面是Eureka的使用场景

从上面看Eureka Server担任注册中心的角色,提供了服务的发现和注册功能。

Service Provider服务提供者,将自身的服务注册到Eureka Server,同时通过心跳检查服务的运行状态。

Service Consumer服务调用者,从Eureka Server得到注册的服务列表,找到对应的服务地址调用并使用。

二、Eureka核心概念

1、Eureka Server:注册中心服务端

注册中心服务端主要对外提供了三个功能:

(1)服务注册

服务提供者启动时,会通过Eureka Client向Eureka Server注册信息,Eureka Server会存储该服务的信息,Eureka Server内部有二层缓存机制来维护整个注册表。

(2)提供注册表

服务消费者在调用服务时,如果Eureka Client没有缓存注册表的话,会从Eureka Server获取最新的注册表。

(3)同步状态

Eureka Client通过注册、心跳机制和Eureka Server同步当前客户端的状态。

2、Eureka Client:注册中心客户端

Eureka Client是一个java客户端,用于简化与Eureka Server的交互。Eureka Client会拉取、更新、缓存Eureka Server中的信息。因此当所有的Eureka Server节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务的提供者,但是当服务有更改的时候会出现信息不一致。

3、Register:服务注册

服务的提供者,将自身注册到注册中心,服务提供者也是一个Eureka Client。当Eureka Client向Eureka Server注册时,它提供自身的元数据,比如IP地址、端口、运行状况指示符URL、主页等。

4、Renew:服务续约

Eureka Client会每隔30秒发送一次心跳来续约。通过续约来告知Eureka Server该Eureka Client运行正常,没有出现问题。默认情况下,如果Eureka Server在90秒内没有收到Eureka Client的续约,Server端会将实例从其注册表中删除,此事件可配置,一般情况不建议更改。

5、Eviction服务剔除

当Eureka Client和Eureka Server不再有心跳时,Eureka Server会将服务实例从服务注册列表中删除,即服务剔除。

6、Cancel:服务下线

Eureka Client在程序关闭时想Eureka Server发送取消请求,发送请求后,该客户端实例信息将从Eureka Server的实例注册表中删除。该下线请求不会自动完成,它需要调用一下内容:

DiscoveryManager.getInstance().shutdownComponent();

7、GetRegistry:获取注册列表信息

Eureka Client从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒)更新一次。每次返回注册列表信息可能与Eureka Client的缓存信息不同,Eureka Client自动处理。

如果由于某种原因导致注册信息列表信息不能及时匹配,Eureka Client则会重新获取整个注册表信息。Eureka Server缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka Client和Eureka Server可以使用JSON/XML格式进行通讯。在默认情况下Eureka Client使用压缩JSON形式来获取注册列表的信息。

8、Remote Call:远程调用

当Eureka Client从注册中心获取到服务提供者信息后,就可以通过HTTP请求调用对应的服务;服务提供者有多个时,Eureka Client客户端会自动通过Ribbon自动进行负载均衡。

三、自我保护机制

默认请款下,如果Eureka Server在90秒内没有接收到某个微服务实例的心跳,会注销该实例。但是在微服务架构下服务之间通常都是跨进程调用,网络通信往往面临很多问题,比如微服务状态正常,网络分区故障,导致此实例被注销。

固定时间内大量实例被注销,可能会严重威胁某个微服务架构的可用性,为了解决这个问题,Eureka开发了自我保护机制,那么什么是自我保护机制呢?

Eureka Server在运行期间会去统计心跳失败比例在15分钟之内是否低于85%,如果低于85%,Eureka Server即进入自我保护机制。

Eureka Server触发自我保护机制后,页面会出现提示:

Eureka Server进入自我保护机制,会出现以下几种情况:

(1)Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。

(2)Eureka仍然能够接受新服务的注册和查询,但是不会被同步到其它节点上(即保证当前节点依然可用)。

(3)当网络稳定后,当前实例新的注册信息会被同步到其它节点上。

Eureka自我保护机制是为了防止误杀服务而提供的一种机制。当个别客户端出现心跳失联时,则认为是客户端的问题,剔除客户端;当Eureka 捕获到大量的心跳失败时,则认为可能是网络问题,进入自我保护机制;当客户端心跳恢复时,Eureka会自动退出自我保护机制。

如果在保护期内刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一无效的服务实例,则会调用失败。对于这个问题需要服务消费者要有一些容错机制,比如重试,断路器等。

四、Eureka高可用集群

理论上来讲,服务消费者本地缓存了服务提供者的地址,即使Eureka Server宕机,也不会影响服务之间的调用,但是一旦涉及到服务的上下线,本地的缓存信息将会出现偏差,影响整个微服务的稳定性,因此搭建Eureka Server集群来提高整个架构的高可用性,是非常必要的。

从图中可以看出Eureka Server集群相互之间通过Replicate来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册提高可用性,每个节点需要添加一个或多个有效的serviceURL指向其他节点。

如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。

另外 Eureka Server 的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。所以,如果存在多个节点,只需要将节点之间两两连接起来形成通路,那么其它注册中心都可以共享信息。每个 Eureka Server 同时也是 Eureka Client,多个 Eureka Server 之间通过 P2P 的方式完成服务注册表的同步。

Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的。

五、 Eureka分区

Eureka提供了Region和Zone两个概念来进行分区:

 Region:可以理解为地理上的不同区域,比如亚洲地区,中国地区,大连地区等等。没有具体大小的限制。根据项目具体的情况,可以自行合理划分Region。

Zone:可以简单理解为region内的具体机房,比如说region划分为大连,大连有两个机房,就可以再次region之下划分出zone1,zone2两个zone。

六、Eureka保证AP

Eureka Server 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka Client 在向某个 Eureka 注册时,如果发现连接失败,则会自动切换至其它节点。只要有一台 Eureka Server 还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。

七、Eureka工作流程

1、Eureka Server启动成功,等待服务端注册。

在启动过程中如果配置了集群,集群之间定时通过Replicate同步注册表,每个Eureka Server都存在独立完整的服务注册表信息。

2、Eureka Client启动时根据配置的Eureka Server地址去注册中心注册服务。

3、Eureka Client会每30秒向Eureka Server发送一次心跳,证明客户端服务正常。

4、当Eureka Server90秒内没有收到Eureka Client的心跳,注册中心则认为该节点失效,会注销该实例。

5、单位时间内Eureka Server统计到大量的Eureka Client没有发送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有发送心跳的客户端。

6、当Eureka Client心跳恢复正常后,Eureka Server自动退出自我保护机制。

7、Eureka Client定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存在本地。

8、服务调用时,Eureka Client会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存。

9、Eureka Client获取到目标服务器信息,发起服务调用。

10、Eureka Client程序关闭时向Eureka Server发送取消请求,Eureka Server将实例从注册表中剔除。

八、 Eureka  Server数据存储

Eureka  Server的数据存储分为两层:数据存储层和缓存层。

数据存储层记录注册到 Eureka  Server上的服务信息,缓存层是经过包装后的数据,可以直接在 Eureka  Client调用时返回。

Eureka  Server的数据存储层是双层的ConcurrentHashMap,我们知道 ConcurrentHashMap  是线程安全高效的Map集合。

private final ConcurrentHashMap>> registry= new ConcurrentHashMap>>();

第一层的ConcurrentHashMap的key=spring.application.name也就是客户端实例注册的应用名;value为嵌套的ConcurrentHashMap。

第二层嵌套的ConcurrentHashMap的key=instanceId也就是服务的唯一实例id,value为Lease对象,Lease对象存储着这个实例的所有注册信息,包括IP、端口、属性等。

根据这个存储结构我们可以发现,Eureka Server 第一层都是存储着所有的服务名,以及服务名对应的实例信息,也就是说第一层都是按照服务应用名这个维度来切分存储:

应用名1:应用1实例 Map
应该名2:应用2实例 Map
...

第二层是根据实例的唯一 ID 来存储的,那么按照这个结构最终的存储数据格式为:

            :  应用1实例A:实例A的注册信息 

应用名1:应用1实例: 应用1实例B:实例B的注册信息

            :  应用1实例C:实例C的注册信息
            :  ....

            :  应用2实例F:实例F的注册信息 

应该名2:应用2实例: 应用2实例G:实例G的注册信息

            :  ... 

...

数据存储层数据结构如下图所示:

当如服务的状态发生变更时,会同步 Eureka Server 中的 registry 数据信息,比如服务注册、剔除服务时。

九、 Eureka的缓存机制

Eureka Server 为了提供响应效率,提供了两层的缓存结构,将 Eureka Client 所需要的注册信息,直接存储在缓存结构中。

第一层缓存:readOnlyCacheMap,本质上是 ConcurrentHashMap,依赖定时从 readWriteCacheMap 同步数据,默认时间为 30 秒。

readOnlyCacheMap : 是一个 CurrentHashMap的只读缓存,这个主要为了供客户端获取注册信息时使用,其缓存更新,依赖于定时器的更新,通过和 readWriteCacheMap 的值做对比,如果数据不一致,则以 readWriteCacheMap 的数据为准。

第二层缓存: readWriteCacheMap ,本质上是Guava缓存。

readWriteCacheMap:readWriteCacheMap  的数据主要同步于存储层。当获取缓存时判断缓存中是否没有数据, 如果不存在此数据,则通过 CacheLoader 的 load 方法去加载,加载成功之后将数据放入缓存,同时返回数据。

readWriteCacheMap 缓存过期时间,默认为 180 秒,当服务下线、过期、注册、状态变更,都会来清除此缓存中的数据。

Eureka Client 获取全量或者增量的数据时,会先从一级缓存中获取;如果一级缓存中不存在,再从二级缓存中获取;如果二级缓存也不存在,这时候先将存储层的数据同步到缓存中,再从缓存中获取。

通过 Eureka Server 的二层缓存机制,可以非常有效地提升 Eureka Server 的响应时间,通过数据存储层和缓存层的数据切割,根据使用场景来提供不同的数据支持。

十、代码实例

1、项目架构:

2、Eureka服务端application.yml

server:
port: 9000
eureka:
instance:

hostname: localhost

client:

register-with-eureka: false
fetch-registry: false
service-url:
  defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
instance:
  prefer-ip-address: true

3、客户端启动类

package cn.itcast.product;

...

@SpringBootApplication
@EntityScan("cn.itcast.product.entity")
@EnableEurekaClient
public class ProductServiceApplication {
public static void main(String[] args) {

  SpringApplication.run(ProductServiceApplication.class, args);

}
}

4、一些基本的controller、service、bean就不写了,使用的是spring data jpa方式查询的数据库。

5、启动服务

Eureka Server --> Eureka Providor --> Eureka Consumer

Eureka Server

6、Eureka Consumer调用服务

十一、总结

讲解了 Eureka核心概念、 Eureka自我保护机制、 Eureka高可用集群。通过分析 Eureka工作原理,可以明显地感受到 Eureka设计之巧妙,通过一系列的机制,完美的解决了注册中心的稳定性和高可用性。

Eureka 为了保障注册中心的高可用性,容忍了数据的非强一致性,服务节点的数据可能不一致, Eureka  Client间的数据可能不一致。比较适合跨越多机房、对注册中心服务可用性要求较高的使用场景

你可能感兴趣的:(springcloud,eureka,微服务,分布式,架构)