续约

续约的时候,调用的是服务端的InstanceResource#renewLease办法。调用的是InstanceRegistry.renew办法。

@PUTpublic 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服务启动曾经提过了,这里略。注册胜利后,会进行节点间的复制。

@Overridepublic 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(代码略)公布下线监听。

@DELETEpublic Response cancelLease(        @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {    //其余略    boolean isSuccess = registry.cancel(app.getName(), id,            "true".equals(isReplication));    //其余略}

InstanceRegistry#cancel调用PeerAwareInstanceRegistryImpl#cancel,下线胜利后,会进行节点间的复制。

@Overridepublic 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,这个是外围代码。这里会设置勾销工夫戳,并过期读写缓存。

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