spring cloud:eureka源码之我见(五)抓取注册信息

eureka client在第一次启动的时候,必须从eureka server端一次性抓取全量注册信息,在本地进行缓存,然后每隔30s从eureka server抓取增量的注册信息,跟本地缓存进行合并。

一、全量抓取注册信息

1. 抓取注册表的逻辑位于eureka client的实现类DiscoveryClient的构造中。 

如果配置了需要抓取注册信息,那么eureka client就会在启动的时候启动一次抓取全量注册信息流程。

(1)eureka client初始化的时候,就会自动全量抓取注册信息

(2)先获取本地的Applications缓存(Applications就是所有的服务。一个Application就是一个服务,包含了他自己所有的InstanceInfo,也就是所有的服务实例)

(3)调用jersey client,发送http请求(http://localhost:8080/v2/apps),GET请求,调用eureka server的getApplications restful接口,获取全量注册表,缓存在自己的本地

2.这个时候eureka server是如何处理抓取全量注册信息的请求呢?

首先,我们根据请求的url和类型(get)找到对应的Resource(controller)

ApplicationsResource.getContainers()

这就是eureka server提供的读取全量注册信息的接口方法。

eureka server端在支持eureka client来读取注册信息时,设置了一套多级缓存机制。

ResponseCache

在这里使用了两个map,来实现两级缓存,readOnlyCacheMap(只读缓存)和readWriteCacheMap(读写缓存)。如果配置了从只读缓存中获取(默认为true),那么就先读只读缓存,没有,再从读写缓存中获取,然后再放入到只读缓存中。如果没有配置从只读缓存中获取,那么就直接从读写缓存中获取。

如果读写缓存中也没有呢? 

仔细看一下readWriteCacheMap的实现他是一个LoadCache,缓存中有对应的值则返回,没有则使用CacheLoader load方法。而load方法是从注册表registry(也就是当前被请求的eureka server的PeerAwareInstanceRegistryImpl)中读取。从注册表中获取所有的Applications、ServerCodecs(json序列化的组件),将Applications序列化成一个json字符串,将从注册表读取出来的Applications,放入读写缓存,再放入只读缓存。

二、多级缓存的过期机制

1、主动过期

readWriteCacheMap,读写缓存

当有新的服务实例发生注册、下线、故障的时候,就会去刷新readWriteCacheMap

以新服务实例注册为例,eureka server服务下线,删除、更新、新增的接口都在InstanceResource中。具体的实现在注册表PeerAwareInstanceRegistryImpl中。

invalidateCache(appName, vip, svip);

这就是readWriteCache主动过期的代码。

这里会调用responseCache.invalidate()方法,当有新的服务实例注册时,就会将ALL_APPS这个key在readWriteCacheMap中对应的缓存删除。

2、定时过期

在readWriteCacheMap的构造中设置了过期时间,默认180s

expireAfterWrite(serverConfig.getResponseCacheAutoExpirationInSeconds(), TimeUnit.SECONDS)

3、被动过期

readOnlyCacheMap

在ResponseCacheImpl的构造中,如果shouldUseReadOnlyResponseCache的配置为true的话(默认为true),则会启动一个定时任务getCacheUpdateTask(),默认每隔30s执行一次,以readWriteCacheMap数据为准,对readOnlyCacheMap中的数据进行校验,如果不符合,则将readWriteCacheMap中的数据放入readOnlyCacheMap中。

综上,我们可以知道,如果shouldUseReadOnlyResponseCache为true的话,从readOnlyCacheMap中读取注册信息会有最长30s的延迟。也就是说,当eureka client启动时拉取全量注册信息时,拉取到的可能是30s之前的注册信息。如果这个时候有服务实例下线,注册、故障的话,eureka client可能感知不到。

三、增量拉取注册信息

eureka client启动的时候会开启很多定时调度

initScheduledTasks();

其中,就有增量拉取注册信息的调度任务。

每隔30s执行一次,会发送一次http请求给eureka server,拉取增量注册信息。

什么叫做增量呢?就是说和上一次抓取的注册信息做对比,有变化的部分拉取过来就行,不需要全量获取。

增量抓取流程:

(1)定时任务,每隔30秒来一次

(2)因为本地已经有了缓存的Applications,所以再次抓取注册表的时候,走的是增量抓取的策略

(3)发送http请求,http://localhost:8080/v2/apps/delta,get请求

(4)eureka server收到请求,走ApplicationsResource.getContainerDifferential()方法

(5)这里同样从多级缓存机制中获取,缓存的key,ALL_APPS_DELTA。与全量拉取注册信息唯一的区别在于,在readWriteCacheMap中从注册表中获取数据的地方不一样。这里使用registry.getApplicationDeltasFromMultipleRegions()获取增量的注册表,就是从上一次拉取注册信息之后,有变化的注册信息。

(6)recentlyChangedQueue,代表的含义是最近有变化的服务实例,比如说新注册、下线的、或者是故障的等等。在registry(PeerAwareInstanceRegistryImpl)构造的时候,会启动一个定时调度任务,延迟30s之后运行,然后每隔30s调度一次。运行时会检查recentlyChangedQueue中的RecentlyChangedItem的最近更新时间,如果与当前时间的间隔超过180s,则将其从队列中移出。也就是说,这个queue中保留的是最近三分钟发生过变化的服务实例。

(7)eureka client每隔30s去抓取注册信息的时候,就会返回最近3分钟内发生过变化的服务实例。

(8)抓取到的delta注册信息,就会和本地的注册信息合并,完成服务实例的增删改。

(9)计算更新合并完以后的Applications(注册信息)的hash值:reconcileHashCode,而增量注册信息delta也携带了一个eureka server端的全量注册信息hash值,此时将这两个hash值进行比较,如果不一样,则说明client端的注册信息与server端不一致,触发全量拉取注册信息流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值