Eureka - Client服務啓動

咱們從下面的圖能夠看出,做爲一個client端,他有如下功能:spring

  • Register(服務註冊):向Eureka Server註冊自身的信息,好比IP地址、端口等。
  • Renew(服務續約):服務啓動後,每隔30秒會向Eureka Server發送心跳進行服務續約。
  • Get(服務發現):獲取向Eureka Server註冊的服務列表,並緩存本地,默認30秒。
  • Cancel(服務下線):向Eureka Server發送下線信息,Eureka Server會把這個服務標誌爲下線。

image

服務啓動

springboot的自動裝配讀取Eureka Client的spring.factories文件,咱們看到他裏面有多個EnableAutoConfiguration,主要的類是EurekaClientAutoConfiguration。EurekaClientAutoConfiguration類中有多個bean的加載,咱們先看看EurekaInstanceConfigBean的加載。緩存

EurekaInstanceConfigBean

EurekaInstanceConfigBean有個@ConfigurationProperties("eureka.instance")註解,因此咱們在配置文件裏寫的eureka.instance.instanceId這類的信息最終都在賦值給這個類。還有比較重要的leaseRenewalIntervalInSeconds續約頻率(默認每30秒)、leaseExpirationDurationInSeconds續約過時時間(默認90秒)都是在這個類配置的。springboot

@Bean
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class,
        search = SearchStrategy.CURRENT)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils,
        ManagementMetadataProvider managementMetadataProvider) {
    // 省略部分代碼
    EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
    // 省略部分代碼
    return instance;
}

ApplicationInfoManager

ApplicationInfoManager也是在EurekaClientAutoConfiguration類中。
建立eurekaApplicationInfoManager對象的時候,會先建立InstanceInfo對象,InstanceInfo對象的值大部分是從EurekaInstanceConfig複製過來的,另外租約信息是存放在InstanceInfo的leaseInfo中。
因此初始化ApplicationInfoManager的時候,就是賦值EurekaInstanceConfig和InstanceInfo。網絡

@Bean
@ConditionalOnMissingBean(value = ApplicationInfoManager.class,
        search = SearchStrategy.CURRENT)
@org.springframework.cloud.context.config.annotation.RefreshScope
@Lazy
public ApplicationInfoManager eurekaApplicationInfoManager(
        EurekaInstanceConfig config) {
    InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
    return new ApplicationInfoManager(config, instanceInfo);
}

EurekaClientConfigBean

EurekaClientConfigBean也是一個配置信息的bean,他主要是EurekaClient和EurekaServer相關的信息,好比EurekaServer的地址defaultZone、是否從註冊中心拉取註冊信息fetchRegistry(默認true),拉取的頻率registryFetchIntervalSeconds(默認每30秒)、是否向註冊中心註冊registerWithEureka(默認true)等。app

@Bean
@ConditionalOnMissingBean(value = EurekaClientConfig.class,
        search = SearchStrategy.CURRENT)
public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
    return new EurekaClientConfigBean();
}

EurekaClient

建立一個EurekaClient類,這個類就是負責服務的註冊、續約、取消、獲取註冊列表。dom

@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(value = EurekaClient.class,
        search = SearchStrategy.CURRENT)
@org.springframework.cloud.context.config.annotation.RefreshScope
@Lazy
public EurekaClient eurekaClient(ApplicationInfoManager manager,
        EurekaClientConfig config, EurekaInstanceConfig instance,
        @Autowired(required = false) HealthCheckHandler healthCheckHandler) {
    ApplicationInfoManager appManager;
    if (AopUtils.isAopProxy(manager)) {
        appManager = ProxyUtils.getTargetObject(manager);
    }
    else {
        appManager = manager;
    }
    CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager,
            config, this.optionalArgs, this.context);
    cloudEurekaClient.registerHealthCheck(healthCheckHandler);
    return cloudEurekaClient;
}

結合上面幾個類的加載以及EurekaClient的加載,咱們能夠知道這幾個類的關係以下:
image.png
在DiscoveryClient的構造函數裏,主要是初始化一些配置參數,以及爲拉取註冊表信息、初始化定時任務。ide

@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
        Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
    // 初始化applicationInfoManager、config等略

    try {
        // 建立核心數爲2的線程池,一個用於heartbeat,一個用於cacheRefresh
        // default size of 2 - 1 each for heartbeat and cacheRefresh
        scheduler = Executors.newScheduledThreadPool(2,
                new ThreadFactoryBuilder()
                        .setNameFormat("DiscoveryClient-%d")
                        .setDaemon(true)
                        .build());

        heartbeatExecutor = new ThreadPoolExecutor(
                1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(),
                new ThreadFactoryBuilder()
                        .setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
                        .setDaemon(true)
                        .build()
        );  // use direct handoff

        cacheRefreshExecutor = new ThreadPoolExecutor(
                1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(),
                new ThreadFactoryBuilder()
                        .setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d")
                        .setDaemon(true)
                        .build()
        );  // use direct handoff
        // 與EurekaServer網絡通訊用的
        eurekaTransport = new EurekaTransport();
        scheduleServerEndpointTask(eurekaTransport, args);
        //其餘的略
        
    } catch (Throwable e) {
        throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
    }
    
    if (clientConfig.shouldFetchRegistry()) {
        try {
            // 拉取註冊表信息
            boolean primaryFetchRegistryResult = fetchRegistry(false);
            //其餘的略,沒有拉取成功從備份註冊中心獲取
        }
    }
    //其餘的略
    // 初始化定時任務
    initScheduledTasks();
    //其餘的略
}

initScheduledTasks,用來開啓更新服務註冊列表和續租的定時任務,以及對EurekaServer的註冊。函數

private void initScheduledTasks() {
    if (clientConfig.shouldFetchRegistry()) {
        // registry cache refresh timer
        // 這個定時任務是更新服務註冊列表
        // 更新頻率
        int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
        // 延遲最大乘數,好比更新頻率是5s,那最大延遲時間就是50s,這個後面講線程的時候會具體說
        int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
        cacheRefreshTask = new TimedSupervisorTask(
                "cacheRefresh",
                scheduler,
                cacheRefreshExecutor,
                registryFetchIntervalSeconds,
                TimeUnit.SECONDS,
                expBackOffBound,
                new CacheRefreshThread()
        );
        scheduler.schedule(
                cacheRefreshTask,
                registryFetchIntervalSeconds, TimeUnit.SECONDS);
    }
    instanceInfoReplicator = new InstanceInfoReplicator(
        this,
        instanceInfo,
        clientConfig.getInstanceInfoReplicationIntervalSeconds(),
        2);
    if (clientConfig.shouldRegisterWithEureka()) {
        // 這個定時任務是續租
        // 續約頻率
        int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
        int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
        logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs);

        // Heartbeat timer
        heartbeatTask = new TimedSupervisorTask(
                "heartbeat",
                scheduler,
                heartbeatExecutor,
                renewalIntervalInSecs,
                TimeUnit.SECONDS,
                expBackOffBound,
                new HeartbeatThread()
        );
        scheduler.schedule(
                heartbeatTask,
                renewalIntervalInSecs, TimeUnit.SECONDS);

        // 其餘的略
        // 註冊到註冊中心
        instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
    } else {
        logger.info("Not registering with Eureka server per configuration");
    }
}

好了,以上對EurekaServer的註冊、續租、註冊表獲取都說起到了,後面再詳細的講解這些內容。fetch

相關文章
相關標籤/搜索