Make writing a habit together! This is the fourth day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details
Eureka Client pull registry process
Success always belongs to those who love to struggle
Eureka Server startup process analysis diagram + source code to explain Eureka Client startup process analysis diagram + source code to explain Eureka Server registry cache logic
Client pulls registration flow logic
Client pull the registry of logic is that if you first opened read-only cache from a read-only cache access to the registry, if only the registry does not exist under the condition of read and write from the cache, if you to read and write cache and no words from registry after pull synchronization to read and write cache, in synchronization to read-only cache
Code core logic
Where to start
If the pull registry is configured on the New DiscoveryClient, the fetchRegistry method is carried out and the parameter is passed as false
if (clientConfig.shouldFetchRegistry()) {
/** * Client pulls registry core logic */
boolean primaryFetchRegistryResult = fetchRegistry(false);
}
Copy the code
Pull core logic
GetAndStoreFullRegistry () is pulled for the first time, getAndUpdateDelta(Applications) is pulled for the incremental if it is not pulled for the first time
private boolean fetchRegistry(boolean forceFullRegistryFetch) {
try {
/** * If the delta pull is not open or the first pull is full pull registry */
Applications applications = getApplications();// Get all local instances
/ / clientConfig shouldDisableDelta () default is false
if(clientConfig.shouldDisableDelta() || (! Strings.isNullOrEmpty(clientConfig.getRegistryRefreshSingleVipAddress())) || forceFullRegistryFetch// False when passed in
|| (applications == null) / / is not null
|| (applications.getRegisteredApplications().size() == 0) // The first startup is 0
|| (applications.getVersion() == -1))
{
/** * pull and cache the full registry */
getAndStoreFullRegistry();
} else {
/** * If incremental pull is configured and the local localRegionApps cache is not empty, go to the incremental pull registry method */getAndUpdateDelta(applications); }}Copy the code
Full pull logic
Through the previously created good eurekaTransport. QueryClient client visit pull registry, set to the local cache localRegionApps
private void getAndStoreFullRegistry(a) throws Throwable {
/** * Get all instance registration information from eureka-server */
Applications apps = null;
/ / clientConfig getRegistryRefreshSingleVipAddress () default is empty,
/ / so go eurekaTransport. QueryClient. GetApplications (remoteRegionsRef. Get ())
EurekaHttpResponse<Applications> httpResponse =
eurekaTransport.queryClient.getApplications(remoteRegionsRef.get())
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
apps = httpResponse.getEntity();
}
/** * if it is not empty to read data from the cache, it is set to the local cache */
localRegionApps.set(this.filterAndShuffle(apps));
}
Copy the code
Pull the full amount of the registry method of AbstractJersey2EurekaHttpClient getApplicationsInternal interface of serviceUrl own configuration, accessed through the framework jersey interface, So look in the ApplicationsResource of eureka-Core’s resource for a get request with a path plus + version number +/apps
private EurekaHttpResponse<Applications>
getApplicationsInternal(String urlPath, String[] regions) {
Response response = null;
// serviceUrl self-configured interface accessed through the Jersey framework,
// So look in the ApplicationsResource of eureka-core
// Path + version number +/apps get request
WebTarget webTarget = jerseyClient.target(serviceUrl).path(urlPath);
if(regions ! =null && regions.length > 0) {
webTarget = webTarget.queryParam("regions", StringUtil.join(regions));
}
Builder requestBuilder = webTarget.request();
addExtraProperties(requestBuilder);
addExtraHeaders(requestBuilder);
response = requestBuilder.accept(MediaType.APPLICATION_JSON_TYPE).get();
Applications applications = null;
if (response.getStatus() == Status.OK.getStatusCode() && response.hasEntity()) {
applications = response.readEntity(Applications.class);
}
return anEurekaHttpResponse(response.getStatus(), applications).
headers(headersOf(response)).build();
}
Copy the code
Go to the ApplicationsResource of eureka-Core’s resource and look for the get request with the path plus + version number +/apps, which is the real method to get the registry
@GET
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) {.../** * build cache key */
Key cacheKey = new Key(Key.EntityType.Application, ResponseCacheImpl.ALL_APPS,
keyType, CurrentRequestVersion.get(), EurekaAccept.fromString(eurekaAccept),
regions);
/** * Fetch the value */ corresponding to the cacheKey in the cache
response = Response.ok(responseCache.get(cacheKey)).build();
}
return response;
}
Copy the code
ResponseCache. Get (cacheKey) obtains the registry information from the read-only cache if it is enabled, or from the read/write cache if it is not present
public String get(final Key key) {
// Whether to enable read-only cache
return get(key, shouldUseReadOnlyResponseCache);
}
String get(final Key key, boolean useReadOnlyCache) {
Value payload = getValue(key, useReadOnlyCache);
if (payload == null || payload.getPayload().equals(EMPTY_PAYLOAD)) {
return null;
} else {
// return the registry
returnpayload.getPayload(); }}Value getValue(final Key key, boolean useReadOnlyCache) {
Value payload = null;
// If true, obtain the cache value of the key from readOnlyCacheMap [ConcurrentHashMap] read-only cache
if (useReadOnlyCache) {
final Value currentPayload = readOnlyCacheMap.get(key);
// Return the value in the cache if it is read
if(currentPayload ! =null) {
payload = currentPayload;
} else {
LoadingCache (); // LoadingCache ();
// And put it in readOnlyCacheMap read-only cachepayload = readWriteCacheMap.get(key); readOnlyCacheMap.put(key, payload); }}else {
// If useReadOnlyCache is false, the value in the cache is fetched from the LoadingCache
payload = readWriteCacheMap.get(key);
}
return payload;
}
Copy the code
Delta pull logic
getAndUpdateDelta(delta); Is the method of incremental pull, create good eurekaTransport. Through before queryClient client visit pull registry, set to the local cache
private void getAndUpdateDelta(Applications applications) throws Throwable {
Applications delta = null;
/ * * * this will go EurekaHttpClient getDelta () method, * http://localhost:8080/v2/apps/delta, get request * /
EurekaHttpResponse<Applications> httpResponse =
eurekaTransport.queryClient.getDelta(remoteRegionsRef.get());
if(httpResponse.getStatusCode() == Status.OK.getStatusCode()) { delta = httpResponse.getEntity(); }}Copy the code
Walking is AbstractJersey2EurekaHttpClient getDelta () method, Call eureka-core’s resource ApplicationsResource and look for @path (“delta”) with Path + version +/apps/delta
public Response getContainerDifferential(
@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) {
// build a cache key of type responsecacheimpl.all_apps_delta
Key cacheKey = new Key(Key.EntityType.Application, ResponseCacheImpl.ALL_APPS_DELTA,
keyType, CurrentRequestVersion.get(),
EurekaAccept.fromString(eurekaAccept), regions);
// Get registry information from the cache
response = Response.ok(responseCache.get(cacheKey)).build();
return response;
}
Copy the code
ResponseCache. Get (cacheKey) cacheKey (responseCache. Get (cacheKey) cacheKey (responseCache. Get (cacheKey) cacheKey (responseCache) cacheKey (cacheKey
if (delta == null) {
// If the incremental pull is empty, go full pull
getAndStoreFullRegistry();
} else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration,
currentUpdateGeneration + 1)) {
String reconcileHashCode = "";
if (fetchRegistryUpdateLock.tryLock()) {
try {
// Update the incremental pull logic
updateDelta(delta);
reconcileHashCode = getReconcileHashCode(applications);
} finally{ fetchRegistryUpdateLock.unlock(); }}Copy the code
To local registry by getting the incremental data update, traverse to get to the increment of information, if you are adding type then join the local registry, no local situation, if is to modify the type of join the local registry, no local situation, if is to remove type then removed from the local, local if some cases
private void updateDelta(Applications delta) {
int deltaCount = 0;
for (Application app : delta.getRegisteredApplications()) {
for (InstanceInfo instance : app.getInstances()) {
Applications applications = getApplications();
if (ActionType.ADDED.equals(instance.getActionType())) {
// Add to local if it is an add type
applications.addApplication(app);
} else if (ActionType.MODIFIED.equals(instance.getActionType())) {
// If the type is modified, add it to the local
applications.addApplication(app);
} else if (ActionType.DELETED.equals(instance.getActionType())) {
// If it is a delete type then remove it from the local, local if it is
Application existingApp = applications.
getRegisteredApplications(instance.getAppName());
if(existingApp ! =null) { existingApp.removeInstance(instance); }}}Copy the code
summary
- The client pulls from the registry, if the read-only cache is configured, it pulls from the read-only cache, if the read-only cache is not available, it pulls from the read/write cache, and if the read/write cache is not available, it pulls from the server
- If it is the first pull or the local cache does not exist, then the full pull is taken
- If it’s not the first pull or if it’s locally available then it takes the incremental pull and puts it in the local cache