聊聊eureka client的HeartbeatThread

聊聊eureka client的HeartbeatThreadjava

本文主要研究下eureka client的HeartbeatThreadgit

DiscoveryClient.initScheduledTasks

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/DiscoveryClient.javagithub

//...
		//int DEFAULT_EXECUTOR_THREAD_POOL_BACKOFF_BOUND = 10;
		int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
        scheduler = Executors.newScheduledThreadPool(2,
                    new ThreadFactoryBuilder()
                            .setNameFormat("DiscoveryClient-%d")
                            .setDaemon(true)
                            .build());

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

        //......
        if (clientConfig.shouldRegisterWithEureka()) {
            int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs);

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

DiscoveryClient在構造器裏頭執行initScheduledTasks方法,裏頭設置了一個HeartbeatThread的調度,間隔時間是renewalIntervalInSecs秒spring

HeartbeatThread

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/DiscoveryClient.javaapp

/**
     * The heartbeat task that renews the lease in the given intervals.
     */
    private class HeartbeatThread implements Runnable {

        public void run() {
            if (renew()) {
                lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
            }
        }
    }

    /**
     * Renew with the eureka service by making the appropriate REST call
     */
    boolean renew() {
        EurekaHttpResponse<InstanceInfo> httpResponse;
        try {
            httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
            logger.debug(PREFIX + "{} - Heartbeat status: {}", appPathIdentifier, httpResponse.getStatusCode());
            if (httpResponse.getStatusCode() == 404) {
                REREGISTER_COUNTER.increment();
                logger.info(PREFIX + "{} - Re-registering apps/{}", appPathIdentifier, instanceInfo.getAppName());
                long timestamp = instanceInfo.setIsDirtyWithTime();
                boolean success = register();
                if (success) {
                    instanceInfo.unsetIsDirty(timestamp);
                }
                return success;
            }
            return httpResponse.getStatusCode() == 200;
        } catch (Throwable e) {
            logger.error(PREFIX + "{} - was unable to send heartbeat!", appPathIdentifier, e);
            return false;
        }
    }

能夠看到renew調用的是sendHeartBeat方法,若是成功的話,則更新lastSuccessfulHeartbeatTimestamp;若是返回404,則表示須要從新註冊,首先標記dirty,而後調用register方法,若是成功則重置dirty屬性。curl

RestTemplateEurekaHttpClient.sendHeartBeat

spring-cloud-netflix-eureka-client-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.javaui

public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id,
			InstanceInfo info, InstanceStatus overriddenStatus) {
		String urlPath = serviceUrl + "apps/" + appName + '/' + id + "?status="
				+ info.getStatus().toString() + "&lastDirtyTimestamp="
				+ info.getLastDirtyTimestamp().toString() + (overriddenStatus != null
						? "&overriddenstatus=" + overriddenStatus.name() : "");

		ResponseEntity<InstanceInfo> response = restTemplate.exchange(urlPath,
				HttpMethod.PUT, null, InstanceInfo.class);

		EurekaHttpResponseBuilder<InstanceInfo> eurekaResponseBuilder = anEurekaHttpResponse(
				response.getStatusCodeValue(), InstanceInfo.class)
						.headers(headersOf(response));

		if (response.hasBody())
			eurekaResponseBuilder.entity(response.getBody());

		return eurekaResponseBuilder.build();
	}

sendHeartBeat方法是一個PUT請求,參數在url中url

實例debug

curl -i -X PUT http://localhost:8761/eureka/apps/test-service/test1?status=UP&lastDirtyTimestamp=1525767406400&overriddenstatus=UP

返回rest

HTTP/1.1 200
Content-Type: application/xml
Content-Length: 0
Date: Tue, 08 May 2018 08:17:46 GMT

小結

eureka client在實例化的時候註冊了一個定時任務,每隔renewalIntervalInSecs,向eureka server發送一次心跳。

doc

相關文章
相關標籤/搜索