服務(wù)下線的大致流程圖
??下面這張圖很簡單地描述了Server端服務(wù)下線的大致流程:
服務(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ù)約整體的流程大致可以分為以下幾步:
????
????
????
????(注意:清除的是讀寫緩存的數(shù)據(jù))
????
??下面為自己總結(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ī)制