Eureka server end of SpringCloud source code study notes-cancellation of lease

1 Introduction

  In "Eureka Server-Service Renewal" , we learned about the process of processing the renewal on the server. In fact, the process of canceling the lease is similar to the process of renewing the contract. The entrance is also in the InstanceResource class. Let's start learning here The process of canceling the lease.

2. The process of canceling the lease

  The process of canceling a lease on the server is similar to the process of renewing a lease, and is basically as follows:

  1. First, use the cancelLease() method of the InstanceResource class as the entrance to receive and process the request to cancel the lease
  2. Then, call the cancel() method of the InstanceRegistry class, which mainly realizes the broadcast of the EurekaInstanceCanceledEvent event message
  3. Then, the cancel() method of the parent class PeerAwareInstanceRegistryImpl is called. Here, the information synchronization of each node between the clusters is realized after the successful cancellation operation by calling the parent class.
  4. Finally, call the cancel() method of the AbstractInstanceRegistry abstract class. This is where the service lease cancellation is really realized

3. Entrance to cancel the lease request

  The cancelLease() method of the InstanceResource class is the entrance for the Eureka service to cancel the lease. This method ultimately cancels the lease by calling the registry.cancel() method.

@DELETE
 public Response cancelLease(@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
    
    
     try {
    
    
     		//取消租约方法调用
         boolean isSuccess = registry.cancel(app.getName(), id,
             "true".equals(isReplication));

         if (isSuccess) {
    
    
             logger.debug("Found (Cancel): {} - {}", app.getName(), id);
             return Response.ok().build();
         } else {
    
    
             logger.info("Not Found (Cancel): {} - {}", app.getName(), id);
             return Response.status(Status.NOT_FOUND).build();
         }
     } catch (Throwable e) {
    
    
         logger.error("Error (cancel): {} - {}", app.getName(), id, e);
         return Response.serverError().build();
     }

}

4. The cancel() method of the InstanceRegistry class

  In the cancel() method of the InstanceRegistry class, the EurekaInstanceCanceledEvent event is broadcasted mainly by calling the handleCancelation() method, and then the cancel() method of the parent class is called to continue processing.

@Override
public boolean cancel(String appName, String serverId, boolean isReplication) {
    
    
	handleCancelation(appName, serverId, isReplication);
	return super.cancel(appName, serverId, isReplication);
}

  The handleCancelation() method is mainly used to handle broadcast events.

private void handleCancelation(String appName, String id, boolean isReplication) {
    
    
	log("cancel " + appName + ", serverId " + id + ", isReplication "
			+ isReplication);
	publishEvent(new EurekaInstanceCanceledEvent(this, appName, id, isReplication));
}

5. The cancel() method of the PeerAwareInstanceRegistryImpl class

  In the cancel() method of the PeerAwareInstanceRegistryImpl class, the information synchronization of each node between the clusters is realized by calling the replicateToPeers() method after the successful cancellation of the operation by calling the parent class. The specific implementation is as follows:

@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;
 }

  In the cancel () method, by calling replicateToPeers () method, and in replicateToPeers () method in turn calls the replicateInstanceActionsToPeers () method, here are used for data synchronization between cluster nodes method, in front of " Eureka server - I have already learned in the blog post of Service Registration . Let's directly look at the relevant code for canceling the lease in the replicateInstanceActionsToPeers() method as follows:

node.cancel(appName, id);
5.1, the cancel() method of the PeerEurekaNode class

  Through the above code, we can know that, in fact, the cancellation of lease data synchronization is finally realized through the cancel() method of PeerEurekaNode. In this method, the synchronization task InstanceReplicationTask is first constructed, and then the task is executed through the batchingDispatcher.process() method. The specific implementation is as follows:

public void cancel(final String appName, final String id) throws Exception {
    
    
     long expiryTime = System.currentTimeMillis() + maxProcessingDelayMs;
     batchingDispatcher.process(
             taskId("cancel", appName, id),
             new InstanceReplicationTask(targetHost, Action.Cancel, appName, id) {
    
    
                 @Override
                 public EurekaHttpResponse<Void> execute() {
    
    
                     return replicationClient.cancel(appName, id);
                 }

                 @Override
                 public void handleFailure(int statusCode, Object responseEntity) throws Throwable {
    
    
                     super.handleFailure(statusCode, responseEntity);
                     if (statusCode == 404) {
    
    
                         logger.warn("{}: missing entry.", getTaskName());
                     }
                 }
             },
             expiryTime
     );
 }

Among them, the batchingDispatcher.process() method is mainly used to process the task InstanceReplicationTask object and execute the replicationClient.cancel() method. For details, please refer to "Eureka Source Code Analysis-Task Batch Processing" .

5.2, the cancel() method of the AbstractJerseyEurekaHttpClient class

  The cancel() method of the AbstractJerseyEurekaHttpClient class is based on the service cancellation request built by Jersey.

@Override
 public EurekaHttpResponse<Void> cancel(String appName, String id) {
    
    
     String urlPath = "apps/" + appName + '/' + id;
     ClientResponse response = null;
     try {
    
    
         Builder resourceBuilder = jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder();
         addExtraHeaders(resourceBuilder);
         response = resourceBuilder.delete(ClientResponse.class);
         return anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build();
     } finally {
    
    
         if (logger.isDebugEnabled()) {
    
    
             logger.debug("Jersey HTTP DELETE {}/{}; statusCode={}", serviceUrl, urlPath, response == null ? "N/A" : response.getStatus());
         }
         if (response != null) {
    
    
             response.close();
         }
     }
 }

6. The cancel() method of the AbstractInstanceRegistry class

  Finally, the cancellation of the service lease is realized by calling the cancel() method of the AbstractInstanceRegistry abstract class. Here is where the cancellation of the service lease is really realized. In the cancel() method, the internalCancel() method is called again, as shown below:

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

  The logic of canceling the service lease is actually implemented in the internalCancel() method, as follows:

protected boolean internalCancel(String appName, String id, boolean isReplication) {
    
    
    try {
    
    
        read.lock();
        //EurekaMonitors计数
        CANCEL.increment(isReplication);
        //获取appName对应应用的InstanceInfo集合
        Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
        Lease<InstanceInfo> leaseToCancel = null;
        if (gMap != null) {
    
    //获取需要取消租约的Lease<InstanceInfo>对象
            leaseToCancel = gMap.remove(id);
        }
        //维护取消租约的数据,存储到recentCanceledQueue队列中,用于统计或调试
        recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
        //移除overriddenInstanceStatusMap中该对象的重写状态
        InstanceStatus instanceStatus = overriddenInstanceStatusMap.remove(id);
        if (instanceStatus != null) {
    
    
            logger.debug("Removed instance id {} from the overridden map which has value {}", id, instanceStatus.name());
        }
        if (leaseToCancel == null) {
    
    //如果不存在需要取消租约的租约对象,计数、打印日志、并直接返回结果
            CANCEL_NOT_FOUND.increment(isReplication);
            logger.warn("DS: Registry: cancel failed because Lease is not registered for: {}/{}", appName, id);
            return false;
        } else {
    
    //如果存在
        	//记录剔除服务租约的时间(系统当前时间)
            leaseToCancel.cancel();
            //获取租约对应的InstanceInfo 实例
            InstanceInfo instanceInfo = leaseToCancel.getHolder();
            String vip = null;
            String svip = null;
            if (instanceInfo != null) {
    
    
            	//设置instanceInfo对象的变更类型
                instanceInfo.setActionType(ActionType.DELETED);
                //在recentlyChangedQueue队列添加变更记录
                recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
                //修改时间
                instanceInfo.setLastUpdatedTimestamp();
                vip = instanceInfo.getVIPAddress();
                svip = instanceInfo.getSecureVipAddress();
            }
            //使得相关缓存失效
            invalidateCache(appName, vip, svip);
            logger.info("Cancelled instance {}/{} (replication={})", appName, id, isReplication);
        }
    } finally {
    
    
        read.unlock();
    }
	//更新续约的阈值
    synchronized (lock) {
    
    
        if (this.expectedNumberOfClientsSendingRenews > 0) {
    
    
            // Since the client wants to cancel it, reduce the number of clients to send renews.
            this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews - 1;
            updateRenewsPerMinThreshold();
        }
    }

    return true;
}

Guess you like

Origin blog.csdn.net/hou_ge/article/details/111242415