Eureka客户端源码-服务注册&心跳机制


客户端注册流程

客户端向服务端发起注册一共有几个地方呢?

  • 启动初始化的时候发起注册
  • 发送心跳的时候如果服务端返回404,发起注册
  • 客户端缓的存实例信息更新了,发起注册

注册流程客户端代码比较简单,发送post类型的http请求,请求参数为InstanceInfo

boolean register() throws Throwable {
  EurekaHttpResponse httpResponse;
  try {
    httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
  } catch (Exception e) {
    throw e;
  }
  return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}
//AbstractJerseyEurekaHttpClient类中的方法
public EurekaHttpResponse register(InstanceInfo info) {
  String urlPath = "apps/" + info.getAppName();
  ClientResponse response = null;
  try {
    Builder resourceBuilder = jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder();
    addExtraHeaders(resourceBuilder);
    response = resourceBuilder
      .header("Accept-Encoding", "gzip")
      .type(MediaType.APPLICATION_JSON_TYPE)
      .accept(MediaType.APPLICATION_JSON)
      .post(ClientResponse.class, info);
    return anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build();
  }
}

客户端心跳

客户端定时向EurekaServer发送心跳信息 代码如下

private class HeartbeatThread implements Runnable {
  public void run() {
    //续约
    if (renew()) {
      //最后心跳成功的时间戳
      lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
    }
  }
}
boolean renew() {
  EurekaHttpResponse httpResponse;
  try {
    //发送put请求
    httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(),    
                                                      instanceInfo.getId(), instanceInfo, null);
    //服务端响应404 则发起注册,
    if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
      REREGISTER_COUNTER.increment();
      //标记本地的instanceInfo是脏的,返回最后设置脏标识的时间戳
      long timestamp = instanceInfo.setIsDirtyWithTime();
      //服务注册
      boolean success = register();
      if (success) {
        //
        instanceInfo.unsetIsDirty(timestamp);
      }
      return success;
    }
    return httpResponse.getStatusCode() == Status.OK.getStatusCode();
  } catch (Throwable e) {
    return false;
  }
}
public synchronized void unsetIsDirty(long unsetDirtyTimestamp) {
  //判断instanceInfo持有的lastDirtyTimestamp 小于登录 传入进行的时间戳
  //判断的目的在于,还有其他的操作会设置脏标识 例如配置刷新的定时任务,如果客户端的instance配置更新了,
  //则会把本地缓存的instanceInfo设置为脏标识 这个时候 lastDirtyTimestamp就更新了,
  //这个时候实际上本地的instanceInfo和服务器上还不一致,所以还是脏的 所以不能重置 脏标识
  if (lastDirtyTimestamp <= unsetDirtyTimestamp) {
    isInstanceInfoDirty = false;
  } else {
  }
}