Eureka Server的心跳续约就是客户端每隔一段时间向注册中心发送一次心跳,以证明自己没有发生故障。
    下面看下server端的代码

    1. @PUT
    2. public Response renewLease(
    3. @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
    4. @QueryParam("overriddenstatus") String overriddenStatus,
    5. @QueryParam("status") String status,
    6. @QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
    7. // 是否是服务端的同步请求
    8. boolean isFromReplicaNode = "true".equals(isReplication);
    9. // 心跳续约
    10. boolean isSuccess = registry.renew(app.getName(), id, isFromReplicaNode);
    11. // Not found in the registry, immediately ask for a register
    12. if (!isSuccess) {
    13. logger.warn("Not Found (Renew): {} - {}", app.getName(), id);
    14. // 没有续约成功则发回一个NOT_FOUND状态码给客户端
    15. return Response.status(Status.NOT_FOUND).build();
    16. }
    17. // Check if we need to sync based on dirty time stamp, the client
    18. // instance might have changed some value
    19. Response response = null;
    20. if (lastDirtyTimestamp != null && serverConfig.shouldSyncWhenTimestampDiffers()) {
    21. response = this.validateDirtyTimestamp(Long.valueOf(lastDirtyTimestamp), isFromReplicaNode);
    22. // Store the overridden status since the validation found out the node that replicates wins
    23. if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()
    24. && (overriddenStatus != null)
    25. && !(InstanceStatus.UNKNOWN.name().equals(overriddenStatus))
    26. && isFromReplicaNode) {
    27. registry.storeOverriddenStatusIfRequired(app.getAppName(), id, InstanceStatus.valueOf(overriddenStatus));
    28. }
    29. } else {
    30. response = Response.ok().build();
    31. }
    32. logger.debug("Found (Renew): {} - {}; reply status={}", app.getName(), id, response.getStatus());
    33. return response;
    34. }

    当客户端发送心跳连接时将会调用InstanceResource类的renewLease方法

    1. public boolean renew(final String appName, final String id, final boolean isReplication) {
    2. if (super.renew(appName, id, isReplication)) {
    3. // 续约成功,则同步集群
    4. replicateToPeers(Action.Heartbeat, appName, id, null, null, isReplication);
    5. return true;
    6. }
    7. return false;
    8. }
    1. public boolean renew(String appName, String id, boolean isReplication) {
    2. RENEW.increment(isReplication);
    3. // 通过微服务名称拿到服务组
    4. Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
    5. Lease<InstanceInfo> leaseToRenew = null;
    6. if (gMap != null) {
    7. // 根据服务实例id拿到对应的服务实例
    8. leaseToRenew = gMap.get(id);
    9. }
    10. if (leaseToRenew == null) {
    11. RENEW_NOT_FOUND.increment(isReplication);
    12. logger.warn("DS: Registry: lease doesn't exist, registering resource: {} - {}", appName, id);
    13. return false;
    14. } else {
    15. InstanceInfo instanceInfo = leaseToRenew.getHolder();
    16. if (instanceInfo != null) {
    17. // touchASGCache(instanceInfo.getASGName());
    18. InstanceStatus overriddenInstanceStatus = this.getOverriddenInstanceStatus(
    19. instanceInfo, leaseToRenew, isReplication);
    20. if (overriddenInstanceStatus == InstanceStatus.UNKNOWN) {
    21. logger.info("Instance status UNKNOWN possibly due to deleted override for instance {}"
    22. + "; re-register required", instanceInfo.getId());
    23. RENEW_NOT_FOUND.increment(isReplication);
    24. return false;
    25. }
    26. if (!instanceInfo.getStatus().equals(overriddenInstanceStatus)) {
    27. logger.info(
    28. "The instance status {} is different from overridden instance status {} for instance {}. "
    29. + "Hence setting the status to overridden status", instanceInfo.getStatus().name(),
    30. instanceInfo.getOverriddenStatus().name(),
    31. instanceInfo.getId());
    32. instanceInfo.setStatusWithoutDirty(overriddenInstanceStatus);
    33. }
    34. }
    35. renewsLastMin.increment();
    36. // 心跳续约
    37. leaseToRenew.renew();
    38. return true;
    39. }
    40. }
    1. public void renew() {
    2. // duration 默认为90秒,这个可以在配置文件中配置
    3. // 将最后操作时间更新为当前时间+心跳续约时长
    4. lastUpdateTimestamp = System.currentTimeMillis() + duration;
    5. }

    主要步骤:

    • 客户端发送一个心跳续约请求,通过客户端传来的微服务名称和实例id拿到相应的实例对象,
    • 将这个服务的最后操作时间赋值为当前系统时间加上心跳续约时长
    • 同步各个注册集群中的续约时间