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

  1. 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
  2. If it is the first pull or the local cache does not exist, then the full pull is taken
  3. 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