SpringCloud-Netflix(Usage of Eureka)

SpringCloud-Netflix(Usage of Eureka)

前面聊了Ribbon的使用,因为使用Ribbon带出了两个痛点,所以我们来聊聊Eureka,当他和Ribbon结合后,会解决一定的问题。并且本篇会聊聊它的使用,关于SpringCloud-Netflix系列的源码我会在聊完对他们的使用后,然后再和大家进行剖析。

Outline of Eureka

前面说没有Eureka,Ribbon单独使用造成的痛点是【微服务目标地址的维护、监测微服务的健康状态】,那Eureka做的事情其实就是:

  • 服务地址的统一维护
  • 服务提供者的动态上下线感知

要做到上面的两点,Eureka实际上做的事情是非常多的,因为

  • 我们服务调用者需要知道哪些微服务的地址是有用的,那就有两种方式解决
    • 【pull】:服务调用者主动去eureka上获取可用的微服务地址
    • 【push】:eureka主动推送微服务地址给服务调用方,那就需要和这些服务调用方建立心跳,及时的把最新的微服务地址传递给服务调用方
  • eureka需要知道哪些微服务是存活的,那就需要和这些微服务建立心跳

如果Eureka做到了上面的这些,就可以解决Ribbon带来的痛点->Ribbon从Eureka上获取服务地址

  • 自己就不用手动维护地址,解决了目标地址的维护问题
  • Eureka对这些微服务的健康状态进行监听,解决了监测微服务的健康状态

Usage of Eureka

Eureka我们都知道它是一个注册中心,和其他的注册中心不同的是,他也是一个项目,所以我们需要创建一个项目,我们在创建项目的时候,把eureka相关的包勾选上即可。

 

 因为他默认的端口是8761,所在application中修改他的端口为8761,上面说了他是一个项目,所以我们要做还有把他自己注册到自己上面,否则会报错。

spring.application.name=eureka-server
server.port=8761
#自己注册自己
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
View Code

并且在springBoot的启动类上加上@EnableEurekaServer,后面的源码,我会带大家聊这个。启动之后,我们发现,eureka已经把自己注册上去了。

并且在想注册到eureka的微服务中加上eureka的client的pom

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
View Code

同时每个微服务的application中指定一下默认eureka server

eureka.client.service-url.defaultZone=http://localhost:8761/eureka
View Code

这样,我们的相关的微服务在启动的时候就注册到了eureka中

 另外我们需要加上actuator对微服务进行健康检查

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
View Code

这个时候,我们就可以删除在单独使用Ribbon的时候在application中维护的各个微服务地址,Ribbon会从Eureka上获取地址。

Framework of Eureka

 Eureka满足了cap理论中的ap的特性,也就是可用性,和分区容错性,他的集群是一个去中心化的集群节点。因为如果有中心节点,那就会造成短时间内不可用的状态,就像之前的zk一样。引入集群后,他的流程如下:

  • 服务提供者启动的时候把自己注册到eureka上,然后建立心跳包。
  • 客户端通过定时的轮询去获取eureka上的服务地址。
  • 如果服务提供者的请求落到了某个eureka节点上的话,eureka就会把数据同步到其他的eureka节点上

搭建集群】:实际上就是搭建多个相同的eureka项目,然后把彼此注册到对方中,比如我们现在有一个8761的节点,那就在application中维护8762的信息,反之亦然。eureka因为不像zk那样,所以只要保证高可用,无论部署几个节点。

spring.application.name=eureka-server-replica
server.port=8762
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
View Code

eureka的数据同步流程(基于http协议进行api接口之间的通信):

服务提供者随机调用eureka的服务注册/下线api,在eureka底层提供了一个数据副本同步的机制,他会进行多个节点之间的同步
  • 当服务提供这随机调用一个eureka的api,比如说默认到eureka1上,eureka1会首先更新自己节点上的数据,
  • 然后它遍历所有的eureka实例,
  • 最后逐一发送数据同步的请求

问题:那么既然eureka集群没有中心节点,它是如何避免死循环同步问题呢?(比如有一个服务提供者上线,并且发送消息到eureka1这个时候eureka1更新了它本地,并且发送一个他同步数据给了eureka2,这个时候eureka2收到了同步消息,更新了自己的本地,并且把这个数据也同步给了eureka1,这样就造成了死循环)

解决:这个通过加时间戳解决就可以了,判断最新就行,这个和zk的zxid一样,后面源码我会和大家聊。

relevant questions

eureka心跳续约机制的流程

  • 服务提供者每隔30s会发送一次心跳请求给eureka-server,在eureka上维护了所有服务提供者的实例,当一次心跳请求过来的时候,他会更新发送心跳的服务的时间。在eureka上,它会每隔60s去检查所有的实例的过期时间,如果维护的某个服务提供者的上一次的心跳时间距离当前时间大于90s就认为服务提供者过期,并且会剔除它(但是eureka如果开启了自我保护机制是不会剔除

eureka自我保护机制

  • 上面说到当某个服务提供者的心跳时间距离当前的时间大于90s那就被认为已经宕机,然而如果开启了自我保护机制那就不会剔除。这是因为有的时候因为网络的问题,eureka通过心跳判定某个服务提供者可能已经宕机,所以把一个健康的因为网络问题的服务提供者给剔除了。为了规避这种原因,eureka会默认开启这种机制【eureka.server.enable-self-preservation=true/false】.

【什么时候会打开自我保护的开关】:

  • 如果超过85%的客户端节点都没有发起正常的心跳(renew),那么eureka就认为客户端和服务端出现了网络故障eureka就会进入自我保护状态。当然我们可以修改【eureka.server.renewal-percent-threshold = 0.85】。那具体表现为Renews (last min) < Renews threshold。这两个数值我们都可以在eureka的dashboard上看见。

Renews threshold:Eureka Server 期望每分钟收到客户端实例续约的总数。这个数字15分钟更新一次。 (服务总数*每分钟的续约数量(60s/客户端续约间隔时间)* 0.85->现在我们的服务总数为为7个 那就等于【7*2*0.85=11.9(11)】

Renews (last min)】:Eureka Server 最后 1 分钟收到客户端实例续约的总数。

注:这两个参数我们可以在eureka的dashboard中看见。

【模拟自我保护机制】

通过配置,让它在5s之内,保证所有的服务都成功。这显然是不可能的,所以我们这样就可以模拟。

eureka.server.wait-time-in-ms-when-sync-empty=5000
eureka.server.renewal-percent-threshold=1
View Code

Eureka多级缓存机制

他的缓存只是为了解决读写服务提供者信息的冲突问题,从而使用多个容器作为读写分离,他的服务提供者的信息是存储在ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>中的。下面为缓存流程:

  • 当服务注册或者服务下线,这些服务提供者的信息会更新到ConcurrentHashMap,然后同时更新到readWriteCacheHahMap中。
  • 当查询这些服务提供者信息的时候,
    • 他不会直接读取ConcurrentHashMap,而是从只读缓存中获取数据(readOnlyCacheHashMap)。
    • 这个只读缓存(readOnlyCacheHashMap)的信息是从一个readWriteCacheHahMap的容器中同步过来的。
    • readWriteCacheHahMap中的数据是,当ConcurrentHashMap中的信息变更后,就会马上同步到readWriteCacheHahMap
    • readOnlyCacheHashMap会每隔30s从readWriteCacheHahMap中获取数据,readWriteCacheHahMap中的数据每隔180s会过期,过期后会从ConcurrentHashMap中重新同步。

 

posted @ 2021-12-28 16:43  UpGx  阅读(94)  评论(0编辑  收藏  举报