当客户端申请全量更新的时候,会调用 ApplicationsResource#getContainers 这个办法。如果是增量,会调用 ApplicationsResource#getContainerDifferential 这个办法。他次要是获取只读缓存的内容,如果只读缓存不存在,返回只读读写缓存的内容。
public Response getContainers(@PathParam("version") String version,
@HeaderParam(HEADER_ACCEPT) String acceptHeader,
@HeaderParam(HEADER_ACCEPT_ENCODING) String acceptEncoding,
@HeaderParam(EurekaAccept.HTTP_X_EUREKA_ACCEPT) String eurekaAccept,
@Context UriInfo uriInfo,
@Nullable @QueryParam("regions") String regionsStr) {
// 其余略
response = Response.ok(responseCache.get(cacheKey))
.build();
// 其余略
CurrentRequestVersion.remove();
return response;
}
public String get(final Key key) {return get(key, shouldUseReadOnlyResponseCache);
}
@VisibleForTesting
String get(final Key key, boolean useReadOnlyCache) {Value payload = getValue(key, useReadOnlyCache);
if (payload == null || payload.getPayload().equals(EMPTY_PAYLOAD)) {return null;} else {return payload.getPayload();
}
}
@VisibleForTesting
Value getValue(final Key key, boolean useReadOnlyCache) {
Value payload = null;
try {
// 应用只读缓存
if (useReadOnlyCache) {
// 如果只读缓存有值,返回只读缓存的,如果没值,返回读写缓存
final Value currentPayload = readOnlyCacheMap.get(key);
if (currentPayload != null) {payload = currentPayload;} else {payload = readWriteCacheMap.get(key);
readOnlyCacheMap.put(key, payload);
}
} else {payload = readWriteCacheMap.get(key);
}
} catch (Throwable t) {logger.error("Cannot get value for key : {}", key, t);
}
return payload;
}
下面的代码流程如下:
readOnlyCacheMap 的值是怎么来的呢?
Eureka – Server 服务启动 PeerAwareInstanceRegistry#init 办法中提到了 ResponseCacheImpl 构造函数中,没 30 秒会把 readWriteCacheMap 的值赋值给 readOnlyCacheMap。
ResponseCacheImpl 初始化的时候,咱们看到他默认 180 秒后会过期。
this.readWriteCacheMap =
CacheBuilder.newBuilder().initialCapacity(serverConfig.getInitialCapacityOfResponseCache())
.expireAfterWrite(serverConfig.getResponseCacheAutoExpirationInSeconds(), TimeUnit.SECONDS)
// 其余略;
Eureka – Server 服务启动中提到,PeerAwareInstanceRegistryImpl#syncUp() 每次注册都会被动清空 readWriteCacheMap 的值。
ResponseCacheImpl 初始化的时候,还有一个 build 办法
this.readWriteCacheMap =
CacheBuilder.newBuilder().initialCapacity(serverConfig.getInitialCapacityOfResponseCache())
// 其余略
.build(new CacheLoader<Key, Value>() {
@Override
public Value load(Key key) throws Exception {if (key.hasRegions()) {Key cloneWithNoRegions = key.cloneWithoutRegions();
regionSpecificKeys.put(cloneWithNoRegions, key);
}
Value value = generatePayload(key);
return value;
}
});
当 readWriteCacheMap 没有值的时候,他会调用 load 办法。如果是全量,就会调用 registry.getApplications() 这个办法,如果是增量会调用 registry.getApplicationDeltas(),间接从注册表数据拿值。
所以在服务发现的时候,都是走缓存,提高效率,然而为了保证数据的一致性,还会定期更新、清空缓存。