Eureka系列(七) 服務(wù)下線Server端具體實(shí)現(xiàn)

服務(wù)下線的大致流程圖

??下面這張圖很簡單地描述了Server端服務(wù)下線的大致流程:
服務(wù)下線.jpg

服務(wù)下線Server端實(shí)現(xiàn)源碼分析

??Eureka服務(wù)實(shí)現(xiàn)是通過Server端InstanceResource 類 cancelLease 方法來實(shí)現(xiàn)服務(wù)下線操作,下面我們來看看具體實(shí)現(xiàn)代碼:

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

??由上可見,調(diào)用了registry.cancel()方法,我們接著往下看

@Override
public boolean cancel(final String appName, final String id,
                      final boolean isReplication) {
    if (super.cancel(appName, id, isReplication)) {
        // 向其他Server同步服務(wù)下線信息
        replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
        synchronized (lock) {
            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;
}

??由上面我們可以發(fā)現(xiàn),如果調(diào)用super.cancel(appName, id, isReplication)成功,則會(huì)調(diào)用replicateToPeers方法向Server端同步發(fā)送服務(wù)下線消息。我們接著看super.cancel(appName, id, isReplication)的具體實(shí)現(xiàn):

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

??在父類的cancel方法中調(diào)用了internalCancel(appName, id, isReplication)來實(shí)現(xiàn),因此我們繼續(xù)往下看:

protected boolean internalCancel(String appName, String id, boolean isReplication) {
    try {
        read.lock();
        CANCEL.increment(isReplication);
        Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
        Lease<InstanceInfo> leaseToCancel = null;
        if (gMap != null) {
            // 刪除服務(wù)租約信息
            leaseToCancel = gMap.remove(id); 
        }
        synchronized (recentCanceledQueue) {
            // 添加進(jìn)隊(duì)列,方便其他客戶端進(jìn)行批量更新
            recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
        }
        //刪除客戶端狀態(tài)信息
        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 = 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();
            }
            // 刪除緩存信息,并重新加載實(shí)例信息,初始化讀寫緩存
            invalidateCache(appName, vip, svip);
            logger.info("Cancelled instance {}/{} (replication={})", appName, id, isReplication);
            return true;
        }
    } finally {
        read.unlock();
    }
}

總結(jié):
??參考上面internalCancel方法的源碼,以及之前整體調(diào)用的方法,我們可以發(fā)現(xiàn)服務(wù)續(xù)約整體的流程大致可以分為以下幾步:
????\color{red}{1.刪除服務(wù)租約信息}
????\color{red}{2.將下線的服務(wù)放進(jìn)隊(duì)列里,方便其他Client的增量更新操作}
????\color{red}{3.刪除服務(wù)狀態(tài)信息}
????\color{red}{4.刪除緩存信息}(注意:清除的是讀寫緩存的數(shù)據(jù))
????\color{red}{5.向其他Server同步發(fā)送服務(wù)下線消息}


??下面為自己總結(jié)的Eureka相關(guān)的知識(shí)點(diǎn),有興趣地小伙伴可以看一看,當(dāng)然再點(diǎn)下贊就更棒了,創(chuàng)作不易!
??Eureka系列(一)Eureka功能介紹
??Eureka系列(二) 服務(wù)注冊Server端具體實(shí)現(xiàn)
??Eureka系列(三)獲取服務(wù)Client端具體實(shí)現(xiàn)
??Eureka系列(四) 獲取服務(wù)Server端具體實(shí)現(xiàn)
??Eureka系列(五) 服務(wù)續(xù)約流程具體實(shí)現(xiàn)
??Eureka系列(六) TimedSupervisorTask類解析
??Eureka系列(七) 服務(wù)下線Server端具體實(shí)現(xiàn)
??Eureka系列(八)服務(wù)剔除具體實(shí)現(xiàn)
??Eureka系列(九)Eureka自我保護(hù)機(jī)制

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容