SpringCloud源码剖析-Eureka Client服务续约

简介: EureakClient会定时向EureakServer发送续约心跳(默认30s/次) ,来告诉EurekaServer自己的健康状况,默认情况下3次续约失败(90s),EurekaServer考虑剔除续约失败的客户端服务

什么是服务续约

EureakClient会定时向EureakServer发送续约心跳(默认30s/次) ,来告诉EurekaServer自己的健康状况,默认情况下3次续约失败(90s),EurekaServer考虑剔除续约失败的客户端服务

初始化定时任务

在EuerakClient中依然是通过scheduler定时实现,在com.netflix.discovery.DiscoveryClient#initScheduledTasks中进行初始化,源码如下

/*** Initializes all scheduled tasks.*/privatevoidinitScheduledTasks() {
//如果开启服务注册if (clientConfig.shouldRegisterWithEureka()) {
//续约心跳  30s/次intrenewalIntervalInSecs=instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
intexpBackOffBound=clientConfig.getHeartbeatExecutorExponentialBackOffBound();
logger.info("Starting heartbeat executor: "+"renew interval is: {}", renewalIntervalInSecs);
// Heartbeat timer//心跳任务scheduler.schedule(
newTimedSupervisorTask(
"heartbeat",
scheduler,
heartbeatExecutor,
renewalIntervalInSecs,
TimeUnit.SECONDS,
expBackOffBound,
newHeartbeatThread()   //HeartbeatThread心跳的线程            ),
renewalIntervalInSecs, TimeUnit.SECONDS);//心跳时间30s/次        ...省略...                    
/**//心跳任务,本身是一个线程对象* The heartbeat task that renews the lease in the given intervals.*/privateclassHeartbeatThreadimplementsRunnable {
publicvoidrun() {
//调用renew()方法续约if (renew()) {
//记录最后续约成功时间lastSuccessfulHeartbeatTimestamp=System.currentTimeMillis();
       }
    }
 }

服务续约线程HeartbeatThread

这里我们看到,通过scheduler定时执行HeartbeatThread线程,在HeartbeatThread中又调用了Discovery.renew()方法执行服务续约,源码如下

/**使用Rest请求像Eureak进行服务续约* Renew with the eureka service by making the appropriate REST call*/booleanrenew() {
//Http相应对象EurekaHttpResponse<InstanceInfo>httpResponse;
try {
//使用eurekaTransport得到http客户端,发起心跳请求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());
longtimestamp=instanceInfo.setIsDirtyWithTime();
//如果续约返回404,尝试重新发起服务注册,并设置Dirtybooleansuccess=register();
if (success) {
instanceInfo.unsetIsDirty(timestamp);
            }
returnsuccess;
        }
returnhttpResponse.getStatusCode() ==200;
    } catch (Throwablee) {
logger.error(PREFIX+"{} - was unable to send heartbeat!", appPathIdentifier, e);
returnfalse;
    }
}

这里依然使用的是eurekaTransport得到一个EurekaHttpClient实例,然后通过EurekaHttpClientDecorator装饰器执行sendHeartBeat方法,源码如下

publicabstractclassEurekaHttpClientDecoratorimplementsEurekaHttpClient {
    ...省略...
//发送心跳@OverridepublicEurekaHttpResponse<InstanceInfo>sendHeartBeat(finalStringappName, //服务名finalStringid,//服务IDfinalInstanceInfoinfo,//服务注册对象finalInstanceStatusoverriddenStatus) {  //服务注册状态returnexecute(newRequestExecutor<InstanceInfo>() {
@OverridepublicEurekaHttpResponse<InstanceInfo>execute(EurekaHttpClientdelegate) {
//发送心跳returndelegate.sendHeartBeat(appName, id, info, overriddenStatus);
            }
@OverridepublicRequestTypegetRequestType() {
returnRequestType.SendHeartBeat;
            }
        });
    }

通过EurekaHttpClientDecorator 装饰器会先后会执行RetryableEurekaHttpClient(失败重试),RedirectingEurekaHttpClient(重定向到不同的EurekaServer)MetricsCollectingEurekaHttpClient(统计执行情况)针对于各种情况的Http客户端,然后

最终通过AbstractJerseyEurekaHttpClient(JerseyApplicationClient),使用jerseyClient发起心跳请求

publicabstractclassAbstractJerseyEurekaHttpClientimplementsEurekaHttpClient {
@OverridepublicEurekaHttpResponse<InstanceInfo>sendHeartBeat(StringappName, Stringid, InstanceInfoinfo, InstanceStatusoverriddenStatus) {
StringurlPath="apps/"+appName+'/'+id;
ClientResponseresponse=null;
try {
//webResource是对Web请求的封装WebResourcewebResource=jerseyClient.resource(serviceUrl)
                .path(urlPath)
//服务状态 UP                .queryParam("status", info.getStatus().toString())
//最后刷新时间                .queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString());
if (overriddenStatus!=null) {
webResource=webResource.queryParam("overriddenstatus", overriddenStatus.name());
            }
BuilderrequestBuilder=webResource.getRequestBuilder();
addExtraHeaders(requestBuilder);
//发送put请求response=requestBuilder.put(ClientResponse.class);
EurekaHttpResponseBuilder<InstanceInfo>eurekaResponseBuilder=anEurekaHttpResponse(response.getStatus(), InstanceInfo.class).headers(headersOf(response));
if (response.hasEntity()) {
eurekaResponseBuilder.entity(response.getEntity(InstanceInfo.class));
            }
returneurekaResponseBuilder.build();
        } finally {
if (logger.isDebugEnabled()) {
logger.debug("Jersey HTTP PUT {}/{}; statusCode={}", serviceUrl, urlPath, response==null?"N/A" : response.getStatus());
            }
if (response!=null) {
response.close();
            }
        }
    }

这里EureakClient会向EureakServer发送自己的服务状态,以及服务最后续约时间,使用的是PUT发起Rest请求。

总结

  1. DiscoveryClient.initScheduledTasks初始化续约心跳定时任务,30s/次执行HeartbeatThread线程发送续约请求
  2. HeartbeatThread调用DiscoveryClient.renew()续约
  3. renew方法中使用eurekaTransport得到EureakaHttpClient实例EurekaHttpClientDecorator 装饰器执行请求
  4. EurekaHttpClientDecorator 调用JerseyApplicationClient向EureakServer发送Rest请求,把服务状态和最后的续约时间当做参数
目录
相关文章
|
16天前
|
负载均衡 监控 Java
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
|
4天前
|
运维 Java Nacos
Spring Cloud应用框架:Nacos作为服务注册中心和配置中心
Spring Cloud应用框架:Nacos作为服务注册中心和配置中心
|
23天前
|
Java Spring
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
43 3
|
2天前
|
Java 应用服务中间件 数据库
SpringCloud:服务保护和分布式事务详解
SpringCloud:服务保护和分布式事务详解
23 0
|
4天前
|
缓存 Java Maven
SpringCloud基于Eureka的服务治理架构搭建与测试:从服务提供者到消费者的完整流程
Spring Cloud微服务框架中的Eureka是一个用于服务发现和注册的基础组件,它基于RESTful风格,为微服务架构提供了关键的服务注册与发现功能。以下是对Eureka的详细解析和搭建举例。
21 0
|
2天前
|
Java 微服务 Spring
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
文章介绍了如何利用Spring Cloud Alibaba快速构建大型电商系统的分布式微服务,包括服务限流降级等主要功能的实现,并通过注解和配置简化了Spring Cloud应用的接入和搭建过程。
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
|
30天前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
14243 19
|
2月前
|
人工智能 Java Spring
使用 Spring Cloud Alibaba AI 构建 RAG 应用
本文介绍了RAG(Retrieval Augmented Generation)技术,它结合了检索和生成模型以提供更准确的AI响应。示例中,数据集(包含啤酒信息)被加载到Redis矢量数据库,Spring Cloud Alibaba AI Starter用于构建一个Spring项目,演示如何在接收到用户查询时检索相关文档并生成回答。代码示例展示了数据加载到Redis以及RAG应用的工作流程,用户可以通过Web API接口进行交互。
52443 66
|
1天前
|
Dubbo Java 调度
揭秘!Spring Cloud Alibaba的超级力量——如何轻松驾驭分布式定时任务调度?
【8月更文挑战第20天】在现代微服务架构中,Spring Cloud Alibaba通过集成分布式定时任务调度功能解决了一致性和可靠性挑战。它利用TimerX实现任务的分布式编排与调度,并通过`@SchedulerLock`确保任务不被重复执行。示例代码展示了如何配置定时任务及其分布式锁,以实现每5秒仅由一个节点执行任务,适合构建高可用的微服务系统。
14 0
|
2月前
|
消息中间件 Java 持续交付
Spring Cloud Alibaba 项目搭建步骤和注意事项
Spring Cloud Alibaba 项目搭建步骤和注意事项
421 0
Spring Cloud Alibaba 项目搭建步骤和注意事项