Diagram + source code Eureka Client offline process analysis

Get into the habit of writing together! This is the 7th day of my participation in the "Nuggets Daily New Plan·April Update Challenge", click to view the details of the event

Eureka Client offline process analysis

If life is likened to the artistic conception of creation, then reading is like sunshine - Chi Li

Related articles
Diagram + source code explanation Eureka Server startup process analysis
diagram + source code explanation Eureka Client startup process analysis
diagram + source code explanation Eureka Server registry cache logic
diagram + source code explanation Eureka Client pull registry flow
diagram + source code explanation Eureka Client service registration process
Diagram + source code to explain Eureka Client heartbeat mechanism process

Core flow chart

image.png

Where to start your analysis

    The DiscoveryClient class is actually a client-related class. It stands to reason that the registration method, the offline method and the heartbeat method are all here, so let's take a look at the main methods of this class.
image.png

core method logic

shatdown offline method

    This method is the core method of instance offline, which includes some methods, such as canceling the listener operation, canceling the scheduling task operation, setting the instance as an offline method, canceling the registration of subsequent methods, processing subsequent unnecessary resources, and canceling registration. Monitoring operations

public synchronized void shutdown() {
    if (isShutdown.compareAndSet(false, true)) {
        logger.info("Shutting down DiscoveryClient ...");
    if (statusChangeListener != null && applicationInfoManager != null) {
        applicationInfoManager.
            unregisterStatusChangeListener(statusChangeListener.getId());
    }
    /**
     * 取消调度任务比如心跳、注册表缓存
     */
    cancelScheduledTasks();
    /**
     * 如果应用程序被注册过
     * clientConfig.shouldRegisterWithEureka() &&
     clientConfig.shouldUnregisterOnShutdown() 默认都为true
     */
    if (applicationInfoManager != null && clientConfig.shouldRegisterWithEureka() 
        && clientConfig.shouldUnregisterOnShutdown()) {
        /**
         * 设置实例状态为下线
         */
        applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
        /**
         * 发送下线逻辑给eureka-server端提示当前实例下线处理
         */
        unregister();
    }
    /**
     * 处理后续不需要的资源
     */
    if (eurekaTransport != null) {
        eurekaTransport.shutdown();
    }
    heartbeatStalenessMonitor.shutdown();
    registryStalenessMonitor.shutdown();
    /**
     * 取消监控注册
     */
    Monitors.unregisterObject(this);
    logger.info("Completed shut down of DiscoveryClient");
    }
}
复制代码

Cancel Scheduled Tasks cancelScheduledTasks

    The cancellation of scheduling tasks here is actually those scheduling tasks that are initialized when the client initializes the operation, such as heartbeat tasks, cache operation tasks, etc.

private void cancelScheduledTasks() {
    // 实例复制停止
    if (instanceInfoReplicator != null) {
        instanceInfoReplicator.stop();
    }
   // 心跳执行器关闭
    if (heartbeatExecutor != null) {
        heartbeatExecutor.shutdownNow();
    }
   // 缓存执行器关闭
    if (cacheRefreshExecutor != null) {
        cacheRefreshExecutor.shutdownNow();
    }
    // 调度执行器关闭
    if (scheduler != null) {
        scheduler.shutdownNow();
    }
     // 取消缓存刷新任务
    if (cacheRefreshTask != null) {
        cacheRefreshTask.cancel();
    }
     // 取消心跳任务
    if (heartbeatTask != null) {
        heartbeatTask.cancel();
    }
}
复制代码

unregister logic

    If the instance is not empty, first set the state of the instance to the offline state, then perform the unregister() method operation, and remove the instance through the cancel method of the eurekaTransport.registrationClient client.

void unregister() {
    // It can be null if shouldRegisterWithEureka == false
    if (eurekaTransport != null && eurekaTransport.registrationClient != null) {
            logger.info("Unregistering ...");
    EurekaHttpResponse<Void> httpResponse = eurekaTransport.registrationClient.
        cancel(instanceInfo.getAppName(), instanceInfo.getId());
    }
}
复制代码

    The instance is offline through the cancel operation of AbstractJersey2EurekaHttpClient, and a send request is constructed to go to the eureka-core project to find the cancelLease method in the InstanceResource class. This method is the real offline request logic.

@DELETE
public Response cancelLease(@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) 
                        String isReplication) {
  registry.cancel(app.getName(), id, "true".equals(isReplication));
  return Response.ok().build();
}
复制代码

    Execute the cancel method of PeerAwareInstanceRegistryImpl in the registry, and then synchronize to other service nodes, all need to offline the current instance

@Override
public boolean cancel(final String appName, final String id,
                      final boolean isReplication) {
    // 取消实例操作
    if (super.cancel(appName, id, isReplication)) {
        // 集群同步方法
        replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);

        return true;
    }
    return false;
}

复制代码

    Execute the internalCancel method in the registry, which contains many core methods

Remove current offline instance information from the local read-write cache

    If the local read-write cache is not empty, that is, when the current instance is obtained, then remove its instance from the read-write cache

public boolean cancel(String appName, String id, boolean isReplication) {
    return internalCancel(appName, id, isReplication);
}

protected boolean internalCancel(String appName, String id, boolean isReplication) {
    CANCEL.increment(isReplication);
    Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
    Lease<InstanceInfo> leaseToCancel = null;
    if (gMap != null) {
       //  将服务实例从eureka server的map结构的注册表中移除掉
        leaseToCancel = gMap.remove(id);
    }
    ......
    return true;
}
复制代码

Put the offline instance into the recently offline queue

    Put the recently offline instance into the recently offline queue

  /**
     * 最近有实例下线的队列
     */
    recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), 
                                                   appName + "(" + id + ")"));
    /**
     * 调用了Lease的cancel()方法,里面保存了一个evictionTimestamp
     * 就是服务实例被清理掉,服务实例下线的时间戳
     */
    leaseToCancel.cancel();
  
复制代码

Add to recently changed queue

    Set the current instance to offline operation, and then put it into the recent changes queue

InstanceInfo instanceInfo = leaseToCancel.getHolder();
String vip = null;
String svip = null;
if (instanceInfo != null) {
    // 设置实例的操作类型是删除操作
    instanceInfo.setActionType(ActionType.DELETED);
    // 实例下线进入改变队列
    recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
    instanceInfo.setLastUpdatedTimestamp();
    vip = instanceInfo.getVIPAddress();
    svip = instanceInfo.getSecureVipAddress();
}

复制代码

Invalidate local cache

/**
 * 实例下线无效本地缓存,中清理掉
 * 就是有一个定时的任务,每隔30秒,将readWriteCacheMap和readOnlyCacheMap进行一个同步
 * 下次所有的eureka client来拉取增量注册表的时候,都会发现readOnlyCacheMap里没有,
 * 会找readWriteCacheMap也会发现没有,
 * 然后就会从注册表里抓取增量注册表,此时就会将上面那个recentCHangedQuuee中的记录返回
 */
invalidateCache(appName, vip, svip);
复制代码

Update the expected number of heartbeats

// 下线期待的每次心跳操作
synchronized (lock) {
    if (this.expectedNumberOfClientsSendingRenews > 0) {
        this.expectedNumberOfClientsSendingRenews = 
            this.expectedNumberOfClientsSendingRenews - 1;
        updateRenewsPerMinThreshold();
    }
}
 protected void updateRenewsPerMinThreshold() {
        // serverConfig.getExpectedClientRenewalIntervalSeconds() 默认 30s
        // 60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds() == 2、
        // serverConfig.getRenewalPercentThreshold())
        // 2 * 0.85 也就是期待一分钟内 实例数量*2*0.85个心跳
        this.numberOfRenewsPerMinThreshold = (int)
                (this.expectedNumberOfClientsSendingRenews * 
                 (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds())
                 * serverConfig.getRenewalPercentThreshold());
 }
复制代码

summary

  1. Service offline operation
  2. Remove the current instance from the local cache
  3. Add to recent offline queue and change queue
  4. Invalidate local cache
  5. If the service is removed, the number of instance heartbeats per minute needs to be updated. If an instance is dropped, the heartbeat will be reduced by two times.

Guess you like

Origin juejin.im/post/7083667521022197797