Eureka
客户端更新机制图解还是直接看图来得实在:
这个注册表中含有所有服务的信息,比如服务的IP,端口,实例状态等,在这个商城项目中,用户在浏览商品之后,想买此商品,这时商品服务会去调用订单服务,而获取订单服务的IP和端口就是由Eureka
注册中心中的注册表维护着的。
DiscoveryClient
类解析DiscoveryClient
是Eureka
客户端向Erueka
服务端获取注册表/注册/发送心跳的具体实现类,可以说是我们跟Eureka
客户端打交道最多的一个类了。
Eureka
服务端一般都是公司基础架构部门或者架构师维护,而我们平时使用springcloud
全家桶来进行开发的话,都是使用的Eureka
客户端,只要依赖如下即可:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
关于Eureka
客户端注册表的相关信息,也是围绕DiscoveryClient
来讲解的。
在DiscoverClient
的构造方法中就实现了:
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
......
boolean primaryFetchRegistryResult = fetchRegistry(false);
......
}
// fetchRegistry()最终会调用getAndStoreFullRegistry()
private void getAndStoreFullRegistry(){
...
Applications apps = null;
EurekaHttpResponse<Applications> httpResponse = clientConfig.getRegistryRefreshSingleVipAddress() == null
? eurekaTransport.queryClient.getApplications(remoteRegionsRef.get())
: eurekaTransport.queryClient.getVip(clientConfig.getRegistryRefreshSingleVipAddress(), remoteRegionsRef.get());
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
apps = httpResponse.getEntity();
}
.......
}
建立定时任务:
cacheRefreshTask = new TimedSupervisorTask(
"cacheRefresh",
scheduler,
cacheRefreshExecutor,
registryFetchIntervalSeconds,
TimeUnit.SECONDS,
expBackOffBound,
new CacheRefreshThread()
);
scheduler.schedule(cacheRefreshTask, registryFetchIntervalSeconds, TimeUnit.SECONDS);
定时任务最终会走到拉取注册表的方法:
private boolean fetchRegistry(boolean forceFullRegistryFetch) {
Applications applications = getApplications();
//clientConfig.shouldDisableDelta()默认是false
if (clientConfig.shouldDisableDelta() || forceFullRegistryFetch){
getAndStoreFullRegistry();
}else{
getAndUpdateDelta(applications);
}
applications.setAppsHashCode(applications.getReconcileHashCode());
}
private void getAndUpdateDelta(Applications applications) throws Throwable {
......
//如果从eureka服务端获取的hashcode,和增量注册表+本地注册表合并后的hashcode不一致的话,就得重新拉取全量注册表
if (!reconcileHashCode.equals(delta.getAppsHashCode()) || clientConfig.shouldLogDeltaDiff()) {
reconcileAndLogDifference(delta, reconcileHashCode);
}
......
}
private void reconcileAndLogDifference(Applications delta, String reconcileHashCode) throws Throwable {
......
EurekaHttpResponse<Applications> httpResponse = clientConfig.getRegistryRefreshSingleVipAddress() == null
? eurekaTransport.queryClient.getApplications(remoteRegionsRef.get())
: eurekaTransport.queryClient.getVip(clientConfig.getRegistryRefreshSingleVipAddress(), remoteRegionsRef.get());
Applications serverApps = httpResponse.getEntity();
......
}
这里有关键的两个配置参数:
# 表示每隔多长,去拉取一次注册表
eureka.client.registry-fetch-interval-seconds=30
# 默认是false,如果设置为true,则之后每次拉取的注册表,都是全量注册表,而不是增量的了,个人觉得,如果是eureka客户端应用实例机器配置以及内存配置还不错的话,可以设置为true,否则还是用默认的吧
eureka.client.disable-delta=false
最开始我使用Eureka
时,经常被这两个概念绕晕,但在DiscoverClient
类中得到了答案:
private class HeartbeatThread implements Runnable {
public void run() {
if (renew()) {
lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
特么应用实例发送心跳,其实就是续约啊!!!