Eureka简单源码解析 6.25

erueka的几个特性
1.register 方法的源码,打开eureka-client-1.9.3.jar包下面的DiscoveryClient类
先进入initScheduledTasks,有个instanceInfoReplicator 加载

scheduler = Executors.newScheduledThreadPool(2,
                    new ThreadFactoryBuilder()
                            .setNameFormat("DiscoveryClient-%d")
                            .setDaemon(true)
                            .build());  //2分钟的定时调度任务,设置为守护线程

            heartbeatExecutor = new ThreadPoolExecutor(
                    1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(),
                    new ThreadFactoryBuilder()
                            .setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
                            .setDaemon(true)
                            .build()
            );  // 建立个心跳机制
private void initScheduledTasks()
  {
    if (this.clientConfig.shouldFetchRegistry())
    {
      int registryFetchIntervalSeconds = this.clientConfig.getRegistryFetchIntervalSeconds();
      int expBackOffBound = this.clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
      this.scheduler.schedule(new TimedSupervisorTask("cacheRefresh", this.scheduler, this.cacheRefreshExecutor, registryFetchIntervalSeconds, TimeUnit.SECONDS, expBackOffBound, new CacheRefreshThread()), registryFetchIntervalSeconds, TimeUnit.SECONDS);
    }
    if (this.clientConfig.shouldRegisterWithEureka())
    {
      int renewalIntervalInSecs = this.instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
      int expBackOffBound = this.clientConfig.getHeartbeatExecutorExponentialBackOffBound();
      logger.info("Starting heartbeat executor: renew interval is: {}", Integer.valueOf(renewalIntervalInSecs));
      
      this.scheduler.schedule(new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new HeartbeatThread(null)), renewalIntervalInSecs, TimeUnit.SECONDS);//心跳机制
      
      this.instanceInfoReplicator = new InstanceInfoReplicator(this, this.instanceInfo, this.clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2);
      
      this.statusChangeListener = new ApplicationInfoManager.StatusChangeListener()
      {
        public String getId()
        {
          return "statusChangeListener";
        }
        
        public void notify(StatusChangeEvent statusChangeEvent)
        {
          if ((InstanceInfo.InstanceStatus.DOWN == statusChangeEvent.getStatus()) || 
            (InstanceInfo.InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus())) {
            DiscoveryClient.logger.warn("Saw local status change event {}", statusChangeEvent);
          } else {
            DiscoveryClient.logger.info("Saw local status change event {}", statusChangeEvent);
          }
          DiscoveryClient.this.instanceInfoReplicator.onDemandUpdate();
        }
      };
      if (this.clientConfig.shouldOnDemandUpdateStatusChange()) {
        this.applicationInfoManager.registerStatusChangeListener(this.statusChangeListener);
      }
      this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
    }
    else
    {
      logger.info("Not registering with Eureka server per configuration");
    }
  }
  public void run()
  {
    try
    {
      this.discoveryClient.refreshInstanceInfo();
      
      Long dirtyTimestamp = this.instanceInfo.isDirtyWithTime();
      if (dirtyTimestamp != null)
      {
        this.discoveryClient.register();//调用注册
        this.instanceInfo.unsetIsDirty(dirtyTimestamp.longValue());
      }
    }
    catch (Throwable t)
    {
      Future next;
      logger.warn("There was a problem with the instance info replicator", t);
    }
    finally
    {
      Future next;
      Future next = this.scheduler.schedule(this, this.replicationIntervalSeconds, TimeUnit.SECONDS);
      this.scheduledPeriodicRef.set(next);
    }
  }
}
  
  boolean register()
    throws Throwable
  {
    logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);
    try
    {
      httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);
    }
    catch (Exception e)
    {
      EurekaHttpResponse<Void> httpResponse;
      logger.warn("DiscoveryClient_{} - registration failed {}", new Object[] { this.appPathIdentifier, e.getMessage(), e });
      throw e;
    }
    EurekaHttpResponse<Void> httpResponse;
    if (logger.isInfoEnabled()) {
      logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, Integer.valueOf(httpResponse.getStatusCode()));
    }
    return httpResponse.getStatusCode() == 204;
  }

因为client端向server发送HTTP请求,所以我们继续看eureka-core-1.9.3.jar的注册,如何注册

protected void initEurekaServerContext()
    throws Exception
  {
    EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();
    
    JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
    XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
    
    logger.info("Initializing the eureka client...");
    logger.info(eurekaServerConfig.getJsonCodecName());
    ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);
    
    ApplicationInfoManager applicationInfoManager = null;
    if (this.eurekaClient == null)
    {
      EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext()) ? new CloudInstanceConfig() : new MyDataCenterInstanceConfig();
      
      applicationInfoManager = new ApplicationInfoManager(instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
      
      EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
      this.eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
    }
    else
    {
      applicationInfoManager = this.eurekaClient.getApplicationInfoManager();
    }
    PeerAwareInstanceRegistry registry;
    if (isAws(applicationInfoManager.getInfo()))
    {
      PeerAwareInstanceRegistry registry = new AwsInstanceRegistry(eurekaServerConfig, this.eurekaClient.getEurekaClientConfig(), serverCodecs, this.eurekaClient);
      
      this.awsBinder = new AwsBinderDelegate(eurekaServerConfig, this.eurekaClient.getEurekaClientConfig(), registry, applicationInfoManager);
      this.awsBinder.start();
    }
    else
    {
      registry = new PeerAwareInstanceRegistryImpl(eurekaServerConfig, this.eurekaClient.getEurekaClientConfig(), serverCodecs, this.eurekaClient);
    }
    PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(registry, eurekaServerConfig, this.eurekaClient
    
      .getEurekaClientConfig(), serverCodecs, applicationInfoManager);
    
    this.serverContext = new DefaultEurekaServerContext(eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, applicationInfoManager);
    
    EurekaServerContextHolder.initialize(this.serverContext);
    
    this.serverContext.initialize();
    logger.info("Initialized server context");
    
    int registryCount = registry.syncUp();
    registry.openForTraffic(applicationInfoManager, registryCount);
    
    EurekaMonitors.registerAllStats();
  }

PeerAwareInstanceRegistryImpl类里

  public void register(InstanceInfo info, boolean isReplication)
  {
    int leaseDuration = 90;
    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);
  }

PeerAwareInstanceRegistryImpl 继承了AbstractInstanceRegistry

 public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication)
  {
    try
    {
      this.read.lock();
      Map<String, Lease<InstanceInfo>> gMap = (Map)this.registry.get(registrant.getAppName());
      EurekaMonitors.REGISTER.increment(isReplication);
      if (gMap == null)
      {
        ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap();
        gMap = (Map)this.registry.putIfAbsent(registrant.getAppName(), gNewMap);
        if (gMap == null) {
          gMap = gNewMap;
        }
      }
      Lease<InstanceInfo> existingLease = (Lease)gMap.get(registrant.getId());
      if ((existingLease != null) && (existingLease.getHolder() != null))
      {
        Long existingLastDirtyTimestamp = ((InstanceInfo)existingLease.getHolder()).getLastDirtyTimestamp();
        Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();
        logger.debug("Existing lease found (existing={}, provided={}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
        if (existingLastDirtyTimestamp.longValue() > registrationLastDirtyTimestamp.longValue())
        {
          logger.warn("There is an existing lease and the existing lease's dirty timestamp {} is greater than the one that is being registered {}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
          
          logger.warn("Using the existing instanceInfo instead of the new instanceInfo as the registrant");
          registrant = (InstanceInfo)existingLease.getHolder();
        }
      }
      else
      {
        synchronized (this.lock)
        {
          if (this.expectedNumberOfRenewsPerMin > 0)
          {
            this.expectedNumberOfRenewsPerMin += 2;
            
            this.numberOfRenewsPerMinThreshold = ((int)(this.expectedNumberOfRenewsPerMin * this.serverConfig.getRenewalPercentThreshold()));
          }
        }
        logger.debug("No previous lease information found; it is new registration");
      }
      Lease<InstanceInfo> lease = new Lease(registrant, leaseDuration);
      if (existingLease != null) {
        lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
      }
      gMap.put(registrant.getId(), lease);
      synchronized (this.recentRegisteredQueue)
      {
        this.recentRegisteredQueue.add(new Pair(
          Long.valueOf(System.currentTimeMillis()), registrant
          .getAppName() + "(" + registrant.getId() + ")"));
      }
      if (!InstanceInfo.InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus()))
      {
        logger.debug("Found overridden status {} for instance {}. Checking to see if needs to be add to the overrides", registrant
          .getOverriddenStatus(), registrant.getId());
        if (!this.overriddenInstanceStatusMap.containsKey(registrant.getId()))
        {
          logger.info("Not found overridden id {} and hence adding it", registrant.getId());
          this.overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());
        }
      }
      InstanceInfo.InstanceStatus overriddenStatusFromMap = (InstanceInfo.InstanceStatus)this.overriddenInstanceStatusMap.get(registrant.getId());
      if (overriddenStatusFromMap != null)
      {
        logger.info("Storing overridden status {} from map", overriddenStatusFromMap);
        registrant.setOverriddenStatus(overriddenStatusFromMap);
      }
      InstanceInfo.InstanceStatus overriddenInstanceStatus = getOverriddenInstanceStatus(registrant, existingLease, isReplication);
      registrant.setStatusWithoutDirty(overriddenInstanceStatus);
      if (InstanceInfo.InstanceStatus.UP.equals(registrant.getStatus())) {
        lease.serviceUp();
      }
      registrant.setActionType(InstanceInfo.ActionType.ADDED);
      this.recentlyChangedQueue.add(new RecentlyChangedItem(lease));
      registrant.setLastUpdatedTimestamp();
      invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
      logger.info("Registered instance {}/{} with status {} (replication={})", new Object[] {registrant
        .getAppName(), registrant.getId(), registrant.getStatus(), Boolean.valueOf(isReplication) });
    }
    finally
    {
      this.read.unlock();
    }
  }

最后调用Applicationresource 发post请求

@POST
  @Consumes({"application/json", "application/xml"})
  public Response addInstance(InstanceInfo info, @HeaderParam("x-netflix-discovery-replication") String isReplication)
  {
    logger.debug("Registering instance {} (replication={})", info.getId(), isReplication);
    if (isBlank(info.getId())) {
      return Response.status(400).entity("Missing instanceId").build();
    }
    if (isBlank(info.getHostName())) {
      return Response.status(400).entity("Missing hostname").build();
    }
    if (isBlank(info.getIPAddr())) {
      return Response.status(400).entity("Missing ip address").build();
    }
    if (isBlank(info.getAppName())) {
      return Response.status(400).entity("Missing appName").build();
    }
    if (!this.appName.equals(info.getAppName())) {
      return Response.status(400).entity("Mismatched appName, expecting " + this.appName + " but was " + info.getAppName()).build();
    }
    if (info.getDataCenterInfo() == null) {
      return Response.status(400).entity("Missing dataCenterInfo").build();
    }
    if (info.getDataCenterInfo().getName() == null) {
      return Response.status(400).entity("Missing dataCenterInfo Name").build();
    }
    DataCenterInfo dataCenterInfo = info.getDataCenterInfo();
    if ((dataCenterInfo instanceof UniqueIdentifier))
    {
      String dataCenterInfoId = ((UniqueIdentifier)dataCenterInfo).getId();
      if (isBlank(dataCenterInfoId))
      {
        boolean experimental = "true".equalsIgnoreCase(this.serverConfig.getExperimental("registration.validation.dataCenterInfoId"));
        if (experimental)
        {
          String entity = "DataCenterInfo of type " + dataCenterInfo.getClass() + " must contain a valid id";
          return Response.status(400).entity(entity).build();
        }
        if ((dataCenterInfo instanceof AmazonInfo))
        {
          AmazonInfo amazonInfo = (AmazonInfo)dataCenterInfo;
          String effectiveId = amazonInfo.get(AmazonInfo.MetaDataKey.instanceId);
          if (effectiveId == null) {
            amazonInfo.getMetadata().put(AmazonInfo.MetaDataKey.instanceId.getName(), info.getId());
          }
        }
        else
        {
          logger.warn("Registering DataCenterInfo of type {} without an appropriate id", dataCenterInfo.getClass());
        }
      }
    }
    this.registry.register(info, "true".equals(isReplication));
    return Response.status(204).build();
  }

这样客户端就想服务端注册了端口,并且同步到各个节点
2.renew
DiscoveryClient中方法

  boolean renew()
  {
    try
    {
      EurekaHttpResponse<InstanceInfo> httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, null);
      logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, Integer.valueOf(httpResponse.getStatusCode()));
      if (httpResponse.getStatusCode() == 404)
      {
        this.REREGISTER_COUNTER.increment();
        logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName());
        long timestamp = this.instanceInfo.setIsDirtyWithTime();
        boolean success = register();y
        if (success) {
          this.instanceInfo.unsetIsDirty(timestamp);
        }
        return success;
      }
      return httpResponse.getStatusCode() == 200;
    }
    catch (Throwable e)
    {
      logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, e);
    }
    return false;
  }

在server端中的PeerAwareInstanceRegisteryImpl

  public boolean renew(String appName, String id, boolean isReplication)
  {
    if (super.renew(appName, id, isReplication))
    {
      replicateToPeers(Action.Heartbeat, appName, id, null, null, isReplication);
      return true;
    }
    return false;
  }

3.canel
DiscoveryClient

  void unregister()
  {
    if ((this.eurekaTransport != null) && (this.eurekaTransport.registrationClient != null)) {
      try
      {
        logger.info("Unregistering ...");
        EurekaHttpResponse<Void> httpResponse = this.eurekaTransport.registrationClient.cancel(this.instanceInfo.getAppName(), this.instanceInfo.getId());
        logger.info("DiscoveryClient_{} - deregister  status: {}", this.appPathIdentifier, Integer.valueOf(httpResponse.getStatusCode()));
      }
      catch (Exception e)
      {
        logger.error("DiscoveryClient_{} - de-registration failed{}", new Object[] { this.appPathIdentifier, e.getMessage(), e });
      }
    }
  }

server端

protected boolean internalCancel(String appName, String id, boolean isReplication)
  {
    try
    {
      this.read.lock();
      EurekaMonitors.CANCEL.increment(isReplication);
      Map<String, Lease<InstanceInfo>> gMap = (Map)this.registry.get(appName);
      Lease<InstanceInfo> leaseToCancel = null;
      if (gMap != null) {
        leaseToCancel = (Lease)gMap.remove(id);
      }
      synchronized (this.recentCanceledQueue)
      {
        this.recentCanceledQueue.add(new Pair(Long.valueOf(System.currentTimeMillis()), appName + "(" + id + ")"));
      }
      InstanceInfo.InstanceStatus instanceStatus = (InstanceInfo.InstanceStatus)this.overriddenInstanceStatusMap.remove(id);
      if (instanceStatus != null) {
        logger.debug("Removed instance id {} from the overridden map which has value {}", id, instanceStatus.name());
      }
      if (leaseToCancel == null)
      {
        EurekaMonitors.CANCEL_NOT_FOUND.increment(isReplication);
        logger.warn("DS: Registry: cancel failed because Lease is not registered for: {}/{}", appName, id);
        return false;
      }
      leaseToCancel.cancel();
      InstanceInfo instanceInfo = (InstanceInfo)leaseToCancel.getHolder();
      String vip = null;
      String svip = null;
      if (instanceInfo != null)
      {
        instanceInfo.setActionType(InstanceInfo.ActionType.DELETED);
        this.recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
        instanceInfo.setLastUpdatedTimestamp();
        vip = instanceInfo.getVIPAddress();
        svip = instanceInfo.getSecureVipAddress();
      }
      invalidateCache(appName, vip, svip);
      logger.info("Cancelled instance {}/{} (replication={})", new Object[] { appName, id, Boolean.valueOf(isReplication) });
      return true;
    }
    finally
    {
      this.read.unlock();
    }
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值