共计 4033 个字符,预计需要花费 11 分钟才能阅读完成。
续约
续约的时候,调用的是服务端的 InstanceResource#renewLease 办法。调用的是 InstanceRegistry.renew 办法。
@PUT | |
public Response renewLease(@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication, | |
@QueryParam("overriddenstatus") String overriddenStatus, | |
@QueryParam("status") String status, | |
@QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {boolean isFromReplicaNode = "true".equals(isReplication); | |
boolean isSuccess = registry.renew(app.getName(), id, isFromReplicaNode); | |
// 其余略 | |
return response; | |
} |
InstanceRegistry.renew 会发一个 EventPublish 的续约监听(代码略),而后调用 PeerAwareInstanceRegistryImpl#renew。PeerAwareInstanceRegistryImpl#renew。会调用 AbstractInstanceRegistry#renew,如果胜利,会进行节点间的复制。
public boolean renew(final String appName, final String id, final boolean isReplication) {if (super.renew(appName, id, isReplication)) {replicateToPeers(Action.Heartbeat, appName, id, null, null, isReplication); | |
return true; | |
} | |
return false; | |
} |
AbstractInstanceRegistry#renew,获取续约,如果有的话。
public boolean renew(String appName, String id, boolean isReplication) {RENEW.increment(isReplication); | |
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName); | |
Lease<InstanceInfo> leaseToRenew = null; | |
if (gMap != null) {leaseToRenew = gMap.get(id); | |
} | |
if (leaseToRenew == null) {RENEW_NOT_FOUND.increment(isReplication); | |
logger.warn("DS: Registry: lease doesn't exist, registering resource: {} - {}", appName, id); | |
return false; | |
} else { | |
// 其余略 | |
renewsLastMin.increment(); | |
leaseToRenew.renew(); | |
return true; | |
} | |
} |
Lease#renew,更新 lastUpdateTimestamp 工夫。
public void renew() {lastUpdateTimestamp = System.currentTimeMillis() + duration; | |
} |
综上,续约就是更改 lastUpdateTimestamp 的工夫。
注册
注册调用的是 server 的 ApplicationResource#addInstance,他调用 InstanceRegistry#register,和下面一样,这个会公布注册监听。
public Response addInstance(InstanceInfo info, | |
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { | |
// 其余略 | |
registry.register(info, "true".equals(isReplication)); | |
return Response.status(204).build(); // 204 to be backwards compatible} |
InstanceRegistry#register 会调用 PeerAwareInstanceRegistryImpl#register,理论的注册是 AbstractInstanceRegistry#register 办法,这个办法在 Eureka – Server 服务启动曾经提过了,这里略。注册胜利后,会进行节点间的复制。
@Override | |
public void register(final InstanceInfo info, final boolean isReplication) { | |
int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS; | |
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {leaseDuration = info.getLeaseInfo().getDurationInSecs();} | |
super.register(info, leaseDuration, isReplication); | |
replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication); | |
} |
下线
下线调用的是 InstanceResource#cancelLease,而后他会调用 InstanceRegistry#cancel(代码略)公布下线监听。
@DELETE | |
public Response cancelLease(@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { | |
// 其余略 | |
boolean isSuccess = registry.cancel(app.getName(), id, | |
"true".equals(isReplication)); | |
// 其余略 | |
} |
InstanceRegistry#cancel 调用 PeerAwareInstanceRegistryImpl#cancel,下线胜利后,会进行节点间的复制。
@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; | |
} |
AbstractInstanceRegistry#cancel 会调用 AbstractInstanceRegistry#internalCancel,这个是外围代码。这里会设置勾销工夫戳,并过期读写缓存。
@Override | |
public boolean cancel(String appName, String id, boolean isReplication) {return internalCancel(appName, id, isReplication); | |
} | |
protected boolean internalCancel(String appName, String id, boolean isReplication) {read.lock(); | |
try { | |
// 其余略 | |
// 设置勾销的工夫戳 | |
leaseToCancel.cancel(); | |
// 其余略 | |
// 过期缓存,这里是读写缓存 | |
invalidateCache(appName, vip, svip); | |
} | |
} 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; | |
} |
另外,Eureka – Server 服务启动提到了 EvictionTask#run,他会革除过期的实例,他也会调用 AbstractInstanceRegistry#internalCancel 办法,所以读写缓存的图更改为:
bug
咱们看到,续约的时候 lastUpdateTimestamp = System.currentTimeMillis() + duration;
,判断是否过期的时候,又加了一个 duration,所以他剔除的并不是 90 秒没有心跳的,而是 180 秒没有心跳的。
public boolean isExpired(long additionalLeaseMs) {return (evictionTimestamp > 0 || System.currentTimeMillis() > (lastUpdateTimestamp + duration + additionalLeaseMs)); | |
} |