springcloud源碼之eureka-client服務註冊/心跳機制
前言
之前寫過四篇關於eureka源碼的博客,不過都是基於eureka-server來寫的,本篇基於eureka-client來聊一聊客戶端
是如何服務註冊和發送心跳的
入口
從這個文件點開EurekaClientAutoConfiguration
EurekaClientAutoConfiguration#eurekaClient(ApplicationInfoManager manager,
EurekaClientConfig config) {
return new CloudEurekaClient(manager, config, this.optionalArgs,
this.context);
}
————————————————————————————————————————————————————>
CloudEurekaClient#CloudEurekaClient(省略) {
super(applicationInfoManager, config, args);
//省略
}
————————————————————————————————————————————————————>
DiscoveryClient# DiscoveryClient(省略) {
this(applicationInfoManager, config, args, new Provider<BackupRegistry>() {
private volatile BackupRegistry backupRegistryInstance;
//這個get是拿備用服務,eureka-client不僅僅可以配置集羣服務,還可以配置一些備用的服務,
//如果集羣服務拿不到會去備用服務拿
@Override
public synchronized BackupRegistry get() {
//省略
}
}, randomizer);
}
————————————————————————————————————————————————————>
DiscoveryClient最終的構造器,在DiscoveryClient代碼320行
DiscoveryClient# DiscoveryClient(){
//如果客戶端配置了 既不要註冊到服務中心,也不要從服務中心拿數據,那麼本eureka-client其實就失去了意義,直接return
if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) {
//省略 把很多值置爲null
//直接return
return;
}
//下面是幾行僞代碼
//核心池大小爲2的線程池
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
//心跳機制執行,其實就是定時發送心跳請求給eureka-server告訴它我還活着,不要把我剔除
ThreadPoolExecutor heartbeatExecutor = new ThreadPoolExecutor();
//服務發現機制執行,其實就是定時去eureka-server拿微服務實例數據
ThreadPoolExecutor cacheRefreshExecutor = new ThreadPoolExecutor();
//如果客戶端配置應該從註冊中心拿數據,並且這次fetchRegistry(即服務發現)失敗了,則會從備用服務拿
if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) {
fetchRegistryFromBackup();
}
//如果配置了應該註冊到註冊中心(默認true)&&初始化的時候強制註冊(默認false),所以不做配置的情況下,不會進if
//但沒關係,心跳的時候會註冊的,這個看到後面就懂了
if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
if (!register()) {
throw new IllegalStateException("");
}
}
initScheduledTasks();
}
上面這些代碼就是eureka-client初始化的代碼,到此爲止在默認配置的情況下只進行了一次服務發現,還沒有進行服務註冊
服務註冊+心跳機制
private void initScheduledTasks() {
//省略cacheRefreshTask ,因爲這個是服務發現的任務,下篇博客說
//應該註冊到註冊中心
if (clientConfig.shouldRegisterWithEureka()) {
//心跳的間隔(單位s)
int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
//心跳任務
heartbeatTask = new TimedSupervisorTask(
"heartbeat",
scheduler,
heartbeatExecutor,
renewalIntervalInSecs,
TimeUnit.SECONDS,
expBackOffBound,
new HeartbeatThread()
);
//默認30s執行一次心跳
scheduler.schedule(heartbeatTask,renewalIntervalInSecs, TimeUnit.SECONDS);
HeartbeatThread
private class HeartbeatThread implements Runnable {
public void run() {
if (renew()) {
lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
boolean renew() {
//這裏就是訪問eureka-server的renew續期接口了,在之前的博文說過,不再贅述
EurekaHttpResponse<InstanceInfo> httpResponse =
eurekaTransport.registrationClient.sendHeartBeat
(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
//如果續期失敗(失敗原因:沒有找到要續期的微服務,該微服務已過期)
if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
//續期失敗就轉爲註冊
boolean success = register();
return success;
}
return httpResponse.getStatusCode() == Status.OK.getStatusCode();
}
總結
1:@EnableEurekaClient此註解可加可不加,有點雞肋這個
2:eureka-client初始化過程中會先服務發現,如果失敗會去備用服務拿
3:可以配置EnforceRegistrationAtInit屬性強制初始化的時候就進行服務註冊
4:初始化過程開啓定時器30s執行一次心跳續約,如果心跳續約失敗會進行服務註冊