springcloud 之 eureka 源码解析(7)-EurekaClient服务下线源码分析

EurekaClient服务下线源码分析

前言

1、EurekaClient服务下线整体流程图

EurekaClient服务下线整体流程图.jpg

1、客户端下线源码分析

1.1 shutdown()

/**
 * 1、关闭 EurekaClient,也会发送一个注销的请求到 eureka server
 * Shuts down Eureka Client. Also sends a deregistration request to the
 * eureka server.
 */
@PreDestroy
@Override
public synchronized void shutdown() {
    if (isShutdown.compareAndSet(false, true)) {
        logger.info("Shutting down DiscoveryClient ...");

        // 1、移除 applicaion 状态改变的监听器(这个监听器在 new DiscoveryClient 的时候添加的)
        if (statusChangeListener != null && applicationInfoManager != null) {
            applicationInfoManager.unregisterStatusChangeListener(statusChangeListener.getId());
        }

        // 2、取消定时任务
        cancelScheduledTasks();

        // 3、这里就是向 eureka server 发送的注销的请求
        // If APPINFO was registered
        if (applicationInfoManager != null && clientConfig.shouldRegisterWithEureka()) {
            // 3.1 设置应用管理的状态为 DOWN
            applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
            // 3.3 发送注销的网络请求
            unregister();
        }
	
        // 4、关闭网络组件
        if (eurekaTransport != null) {
            eurekaTransport.shutdown();
        }

        // 5、监控服务关闭
        heartbeatStalenessMonitor.shutdown();
        registryStalenessMonitor.shutdown();

        logger.info("Completed shut down of DiscoveryClient");
    }
}

1.2 unregister(向eureka server 发送的注销请求)

/**
 * unregister w/ the eureka service.
 */
void unregister() {
    // It can be null if shouldRegisterWithEureka == false
    if(eurekaTransport != null && eurekaTransport.registrationClient != null) {
        try {
            logger.info("Unregistering ...");
            // 调用的是 cancel 方法
            EurekaHttpResponse<Void> httpResponse = eurekaTransport.registrationClient.cancel(instanceInfo.getAppName(), instanceInfo.getId());
            logger.info(PREFIX + appPathIdentifier + " - deregister  status: " + httpResponse.getStatusCode());
        } catch (Exception e) {
            logger.error(PREFIX + appPathIdentifier + " - de-registration failed" + e.getMessage(), e);
        }
    }
}

2、EurekaServer接收下线请求源码分析

2.1 cancelLease(InstanceResource 的 cancelLease 方法)

@DELETE
public Response cancelLease(
        @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
    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();
    }
}

2.2 cancel(PeerAwareInstanceRegistryImpl 的 cancel 方法)

@Override
public boolean cancel(final String appName, final String id,
                      final boolean isReplication) {
	// 1、调用 AbstractInstanceRegistry 的  cancel 方法                     
    if (super.cancel(appName, id, isReplication)) {
        // 1.1 复制操作到其他的 eureka server 节点 
        replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
        // 1.2 上锁
        synchronized (lock) {
            // 1.3 更新实例的期望心跳数 -2,然后阈值为期望心跳数 * 0.85
            if (this.expectedNumberOfRenewsPerMin > 0) {
                // Since the client wants to cancel it, reduce the threshold (1 for 30 seconds, 2 for a minute)
                this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin - 2;
                this.numberOfRenewsPerMinThreshold =
                        (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
            }
        }
        return true;
    }
    return false;
}

2.3 cancel(AbstractInstanceRegistry.cancel)

protected boolean internalCancel(String appName, String id, boolean isReplication) {
    try {
        read.lock();
        // 1、取消的统计 +1 
        CANCEL.increment(isReplication);
        // 2、注册表中获取 appName 为  key 的 map
        Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
        // 3、从 map 中移除 leaseInfo 
        Lease<InstanceInfo> leaseToCancel = null;
        if (gMap != null) {
            leaseToCancel = gMap.remove(id);
        }
        
        // 4、最近取消的 Queue 添加该实例
        synchronized (recentCanceledQueue) {
            recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
        }
        
        // 5、overriddenInstanceStatusMap中移除该 id 对应的InstanceStatus信息
        InstanceStatus instanceStatus = overriddenInstanceStatusMap.remove(id);
        if (instanceStatus != null) {
            logger.debug("Removed instance id {} from the overridden map which has value {}", id, instanceStatus.name());
        }
        
        // 6、lease 为空,直接返回  false. CANCEL_NOT_FOUND + 1 
        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 {
            // 7、 lease 取消           
            leaseToCancel.cancel();
            
            // 8、更新 InstanceInfo 信息
            /**
            * 1、ActionType 为 DELETED
            * 2、RecentlyChangedQueue 添加该实例 
            * 3、LastUpdatedTimestamp 更新
            */
            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();
            }
            
            // 9、失效缓存信息
            invalidateCache(appName, vip, svip);
            logger.info("Cancelled instance {}/{} (replication={})", appName, id, isReplication);
            return true;
        }
    } finally {
        read.unlock();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值