Spring的Eureka續(xù)約(心跳檢測)詳解
Eureka 續(xù)約 (心跳檢測)
心跳,eureka client每隔一定的時間,會給eureka server發(fā)送心跳,保持心跳,讓eureka server知道自己還活著,lease renewal,續(xù)約,心跳.
Eureka-Client 向 Eureka-Server 發(fā)起注冊應(yīng)用實(shí)例成功后獲得租約 ( Lease )。 Eureka-Client 固定間隔向 Eureka-Server 發(fā)起續(xù)租( renew ),避免租約過期。
默認(rèn)情況下,租約有效期為 90 秒,續(xù)租頻率為 30 秒。兩者比例為 1 : 3 ,保證在網(wǎng)絡(luò)異常等情況下,有三次重試的機(jī)會。
(1)DiscoveryClient初始化的時候,會去調(diào)度一堆定時任務(wù),其中有一個就是HeartbeatThread,心跳線程

(2)在這里可以看到,默認(rèn)是每隔30秒去發(fā)送一次心跳,每隔30秒執(zhí)行一次HeartbeatTHread線程的邏輯,發(fā)送心跳
(3)這邊的話就是去發(fā)送這個心跳,走的是EurekaHttpClient的sendHeartbeat()方法,//localhost:8080/v2/apps/ServiceA/i-000000-1,走的是put請求
/**
* 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() == Status.NOT_FOUND.getStatusCode()) {
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() == Status.OK.getStatusCode();
} catch (Throwable e) {
logger.error(PREFIX + "{} - was unable to send heartbeat!", appPathIdentifier, e);
return false;
}
}(4)負(fù)責(zé)承接服務(wù)實(shí)例的心跳相關(guān)的這些操作的,是ApplicationsResource,服務(wù)相關(guān)的controller。找到ApplicationResource,再次找到InstanceResource,通過PUT請求,可以找到renewLease方法。
@PUT
public Response renewLease(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
@QueryParam("overriddenstatus") String overriddenStatus,
@QueryParam("status") String status,
@QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
boolean isFromReplicaNode = "true".equals(isReplication);
boolean isSuccess = registry.renew(app.getName(), id, isFromReplicaNode);
// Not found in the registry, immediately ask for a register
if (!isSuccess) {
logger.warn("Not Found (Renew): {} - {}", app.getName(), id);
return Response.status(Status.NOT_FOUND).build();
}
// Check if we need to sync based on dirty time stamp, the client
// instance might have changed some value
Response response;
if (lastDirtyTimestamp != null && serverConfig.shouldSyncWhenTimestampDiffers()) {
response = this.validateDirtyTimestamp(Long.valueOf(lastDirtyTimestamp), isFromReplicaNode);
// Store the overridden status since the validation found out the node that replicates wins
if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()
&& (overriddenStatus != null)
&& !(InstanceStatus.UNKNOWN.name().equals(overriddenStatus))
&& isFromReplicaNode) {
registry.storeOverriddenStatusIfRequired(app.getAppName(), id, InstanceStatus.valueOf(overriddenStatus));
}
} else {
response = Response.ok().build();
}
logger.debug("Found (Renew): {} - {}; reply status={}", app.getName(), id, response.getStatus());
return response;
}(5)通過注冊表的renew()方法,進(jìn)去完成服務(wù)續(xù)約,實(shí)際進(jìn)入AbstractInstanceRegistry的renew()方法
/**
* Marks the given instance of the given app name as renewed, and also marks whether it originated from
* replication.
*
* @see com.netflix.eureka.lease.LeaseManager#renew(java.lang.String, java.lang.String, boolean)
*/
public boolean renew(String appName, String id, boolean isReplication) {
RENEW.increment(isReplication);
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> leaseToRenew = null;
if (gMap != null) {
leaseToRenew = gMap.get(id);
}
if (leaseToRenew == null) {
RENEW_NOT_FOUND.increment(isReplication);
logger.warn("DS: Registry: lease doesn't exist, registering resource: {} - {}", appName, id);
return false;
} else {
InstanceInfo instanceInfo = leaseToRenew.getHolder();
if (instanceInfo != null) {
// touchASGCache(instanceInfo.getASGName());
InstanceStatus overriddenInstanceStatus = this.getOverriddenInstanceStatus(
instanceInfo, leaseToRenew, isReplication);
if (overriddenInstanceStatus == InstanceStatus.UNKNOWN) {
logger.info("Instance status UNKNOWN possibly due to deleted override for instance {}"
+ "; re-register required", instanceInfo.getId());
RENEW_NOT_FOUND.increment(isReplication);
return false;
}
if (!instanceInfo.getStatus().equals(overriddenInstanceStatus)) {
logger.info(
"The instance status {} is different from overridden instance status {} for instance {}. "
+ "Hence setting the status to overridden status", instanceInfo.getStatus().name(),
overriddenInstanceStatus.name(),
instanceInfo.getId());
instanceInfo.setStatusWithoutDirty(overriddenInstanceStatus);
}
}
// 新增 續(xù)租每分鐘次數(shù)
renewsLastMin.increment();
// 設(shè)置 租約最后更新時間(續(xù)租)
leaseToRenew.renew();
return true;
}
}實(shí)際的服務(wù)續(xù)約的邏輯,其實(shí)就是在Lease對象中,更新一下lastUpdateTimestamp這個時間戳,每次續(xù)約,就更新一下,duration這里加了一遍,也是eureka的bug,但是官網(wǎng)并不做修改。
public void renew() {
lastUpdateTimestamp = System.currentTimeMillis() + duration;
}到此這篇關(guān)于Spring的Eureka續(xù)約(心跳檢測)詳解的文章就介紹到這了,更多相關(guān)Eureka續(xù)約內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot 實(shí)現(xiàn)bean手動注入操作
這篇文章主要介紹了springboot 實(shí)現(xiàn)bean手動注入操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
Java并發(fā)系列之ConcurrentHashMap源碼分析
這篇文章主要為大家詳細(xì)分析了Java并發(fā)系列之ConcurrentHashMap源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-03-03
SpringBoot中隨機(jī)鹽值+雙重SHA256加密實(shí)戰(zhàn)
本文主要介紹了SpringBoot中隨機(jī)鹽值+雙重SHA256加密實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
SpringBoot詳細(xì)探究講解默認(rèn)組件掃描
在項(xiàng)目中我們創(chuàng)建了Controller,這個Controller是如何被spring自動加載的呢?為什么Controller必須放在啟動類的同級目錄下呢2022-06-06
SpringMVC源碼之HandlerMapping處理器映射器解析
這篇文章主要介紹了SpringMVC源碼之HandlerMapping處理器映射器解析,在Spring?MVC中,HandlerMapping處理器映射器用于確定請求處理器對象,請求處理器可以是任何對象,只要它們使用了@Controller注解或注解@RequestMapping,需要的朋友可以參考下2023-08-08
Javaweb實(shí)現(xiàn)上傳下載文件的多種方法
本篇文章主要介紹了Javaweb實(shí)現(xiàn)上傳下載文件,有多種實(shí)現(xiàn)方式,需要的朋友可以參考下。2016-10-10

