Eureka客户端源码-本地注册表更新
下载注册表有两种情况:全量下载和增量下载
private boolean fetchRegistry(boolean forceFullRegistryFetch) {
try {
//第一次获取注册表,applications为空或者已经注册到Eureka中的应用size为0
//禁用增量更新、强制全量获取、本地注册表数
//或者配置了vipAddress
Applications applications = getApplications();
if (clientConfig.shouldDisableDelta()
|| (!Strings.isNullOrEmpty(clientConfig.getRegistryRefreshSingleVipAddress()))
|| forceFullRegistryFetch
|| (applications == null)
|| (applications.getRegisteredApplications().size() == 0)
|| (applications.getVersion() == -1)) //Client application does not have latest library supporting delta
{
//全量下载
getAndStoreFullRegistry();
} else {
//增量更新
getAndUpdateDelta(applications);
}
}
// Notify about cache refresh before updating the instance remote status
onCacheRefreshed();
// Update remote status based on refreshed data held in the cache
updateInstanceRemoteStatus();
// registry was fetched successfully, so return true
return true;
}
-
全量下载
全量下载相对来说比较简单
private void getAndStoreFullRegistry() throws Throwable { Applications apps = null; EurekaHttpResponse
httpResponse = clientConfig.getRegistryRefreshSingleVipAddress() == null ? eurekaTransport.queryClient.getApplications(remoteRegionsRef.get()) : eurekaTransport.queryClient.getVip(clientConfig.getRegistryRefreshSingleVipAddress(), remoteRegionsRef.get()); if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) { //从EurekaServer获取所有的注册信息 apps = httpResponse.getEntity(); } if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) { //添加到本地缓存中(把返回的数据顺序进行打算处理,以及过滤掉状态是非在线的服务保留在线服务 //(通过config中的shouldFilterOnlyUpInstances进行配置为 true)) localRegionApps.set(this.filterAndShuffle(apps)); } } -
增量下载
private void getAndUpdateDelta(Applications applications) throws Throwable { Applications delta = null; //获取增量注册表信息 EurekaHttpResponse
httpResponse = eurekaTransport.queryClient. getDelta(remoteRegionsRef.get()); if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) { delta = httpResponse.getEntity(); } //如果增量请求数据为空,则进行全量下载 if (delta == null) { getAndStoreFullRegistry(); } else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) { String reconcileHashCode = ""; if (fetchRegistryUpdateLock.tryLock()) { try { //更新本地注册表 updateDelta(delta); //获取注册表的hashcode信息,感兴趣的可以在跟进去看看具体的实现逻辑 reconcileHashCode = getReconcileHashCode(applications); } finally { fetchRegistryUpdateLock.unlock(); } } // There is a diff in number of instances for some reason // 如果delta获取的的instance数据量和本地注册表的数量不一致 则进行全量下载 if (!reconcileHashCode.equals(delta.getAppsHashCode()) || clientConfig.shouldLogDeltaDiff()) { reconcileAndLogDifference(delta, reconcileHashCode); // this makes a remoteCall } } } private void updateDelta(Applications delta) { int deltaCount = 0; for (Application app : delta.getRegisteredApplications()) { for (InstanceInfo instance : app.getInstances()) { //本地注册表信息 Applications applications = getApplications(); //获取实例的region String instanceRegion = instanceRegionChecker.getInstanceRegion(instance); //判断是否是本地region if (!instanceRegionChecker.isLocalRegion(instanceRegion)) { Applications remoteApps = remoteRegionVsApps.get(instanceRegion); if (null == remoteApps) { remoteApps = new Applications(); remoteRegionVsApps.put(instanceRegion, remoteApps); } //如果是非localRegion则把远程Apps赋值给applications applications = remoteApps; } ++deltaCount; if (ActionType.ADDED.equals(instance.getActionType())) { //从本地注册表中获取Application Application existingApp = applications.getRegisteredApplications(instance.getAppName()); //如果不存在,则把增量更新到的这个app添加到applications中 if (existingApp == null) { //把application添加到注册表中 applications.addApplication(app); } //然后把app的实例信息添加到实例列表里面 //看下面addInstance的注释 applications.getRegisteredApplications(instance.getAppName()).addInstance(instance); } else if (ActionType.MODIFIED.equals(instance.getActionType())) { Application existingApp = applications.getRegisteredApplications(instance.getAppName()); if (existingApp == null) { applications.addApplication(app); } applications.getRegisteredApplications(instance.getAppName()).addInstance(instance); } else if (ActionType.DELETED.equals(instance.getActionType())) { Application existingApp = applications.getRegisteredApplications(instance.getAppName()); if (existingApp != null) { //从本地注册表中移除实例 existingApp.removeInstance(instance); //如果本地注册表中该应用下面没有实例信息了,则移除该应用 if (existingApp.getInstancesAsIsFromEureka().isEmpty()) { applications.removeApplication(existingApp); } } } } } }
public void addInstance(InstanceInfo i) { instancesMap.put(i.getId(), i); synchronized (instances) { //instances 是set类型的,并且instanceInfo重写equals方法, //在更新的时候 如果instanceId不变,不进行移除是不会覆盖的, //所以先进行remove然后在进行add instances.remove(i); instances.add(i); isDirty = true; } }
总结:
- 全量下载时机或者条件
- 第一次获取注册表
- 禁用增量下载
- 配置了VIPaddress
- 增量更新没有获取数据时,进行全量下载
- 增量数据和本地注册表数据的hashcode(或者说instance数量不一致)则进行全量下载