Eureka Server的心跳续约就是客户端每隔一段时间向注册中心发送一次心跳,以证明自己没有发生故障。
下面看下server端的代码
@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);// Not found in the registry, immediately ask for a registerif (!isSuccess) {logger.warn("Not Found (Renew): {} - {}", app.getName(), id);// 没有续约成功则发回一个NOT_FOUND状态码给客户端return Response.status(Status.NOT_FOUND).build();}// Check if we need to sync based on dirty time stamp, the client// instance might have changed some valueResponse response = null;if (lastDirtyTimestamp != null && serverConfig.shouldSyncWhenTimestampDiffers()) {response = this.validateDirtyTimestamp(Long.valueOf(lastDirtyTimestamp), isFromReplicaNode);// Store the overridden status since the validation found out the node that replicates winsif (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()&& (overriddenStatus != null)&& !(InstanceStatus.UNKNOWN.name().equals(overriddenStatus))&& isFromReplicaNode) {registry.storeOverriddenStatusIfRequired(app.getAppName(), id, InstanceStatus.valueOf(overriddenStatus));}} else {response = Response.ok().build();}logger.debug("Found (Renew): {} - {}; reply status={}", app.getName(), id, response.getStatus());return response;}
当客户端发送心跳连接时将会调用InstanceResource类的renewLease方法
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;}
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) {// 根据服务实例id拿到对应的服务实例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 {InstanceInfo instanceInfo = leaseToRenew.getHolder();if (instanceInfo != null) {// touchASGCache(instanceInfo.getASGName());InstanceStatus overriddenInstanceStatus = this.getOverriddenInstanceStatus(instanceInfo, leaseToRenew, isReplication);if (overriddenInstanceStatus == InstanceStatus.UNKNOWN) {logger.info("Instance status UNKNOWN possibly due to deleted override for instance {}"+ "; re-register required", instanceInfo.getId());RENEW_NOT_FOUND.increment(isReplication);return false;}if (!instanceInfo.getStatus().equals(overriddenInstanceStatus)) {logger.info("The instance status {} is different from overridden instance status {} for instance {}. "+ "Hence setting the status to overridden status", instanceInfo.getStatus().name(),instanceInfo.getOverriddenStatus().name(),instanceInfo.getId());instanceInfo.setStatusWithoutDirty(overriddenInstanceStatus);}}renewsLastMin.increment();// 心跳续约leaseToRenew.renew();return true;}}
public void renew() {// duration 默认为90秒,这个可以在配置文件中配置// 将最后操作时间更新为当前时间+心跳续约时长lastUpdateTimestamp = System.currentTimeMillis() + duration;}
主要步骤:
- 客户端发送一个心跳续约请求,通过客户端传来的微服务名称和实例id拿到相应的实例对象,
- 将这个服务的最后操作时间赋值为当前系统时间加上心跳续约时长
- 同步各个注册集群中的续约时间
