技术标签: springcloud spring cloud Spring Cloud深入了解
在文章《Spring Cloud源码分析之Eureka篇第四章:服务注册是如何发起的 》的分析中,我们知道了作为Eureka Client的应用启动时,在com.netflix.discovery.DiscoveryClient类的initScheduledTasks方法中,会做以下几件事:
本章学习的是周期性服务续约的相关代码,对应用如何将自身信息注册到Eureka进行深入了解,原文地址:https://blog.csdn.net/boling_cavalry/article/details/82861618
以下图片来自Netflix官方,图中显示Eureka Client会发起Renew向注册中心做周期性续约,这样其他Eureka client通过Get Registry请求就能获取到新注册应用的相关信息:
本次分析的Spring Cloud版本为Edgware.RELEASE,对应的eureka-client版本为1.7.0;
最准确的说明信息来自Netflix的官方文档,地址:https://github.com/Netflix/eureka/wiki/Understanding-eureka-client-server-communication#renew
学习源码之前先看文档可以确定大方向,不会因为陷入源码细节导致偏离学习目标,如下图所示:
我的理解:
private void initScheduledTasks() {
//略去获取服务列表相关代码
...
if (clientConfig.shouldRegisterWithEureka()) {
//心跳间隔
int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
//周期性任务执行超时的时候,会将超时时间翻倍,但不会超过最大时间,这个最大时间是由expBackOffBound决定的
int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
logger.info("Starting heartbeat executor: " + "renew interval is: " + renewalIntervalInSecs);
//启动心跳的周期性任务
scheduler.schedule(
new TimedSupervisorTask(
"heartbeat",
scheduler,
heartbeatExecutor,
renewalIntervalInSecs,
TimeUnit.SECONDS,
expBackOffBound,
new HeartbeatThread()
),
renewalIntervalInSecs, TimeUnit.SECONDS);
//略去服务注册相关代码
...
上述代码可以看出,续租逻辑在HeartbeatThread实例中,交给TimedSupervisorTask实例进行周期性调用,有关TimedSupervisorTask的功能和细节,请参考《Eureka的TimedSupervisorTask类(自动调节间隔的周期性任务)》;
HeartbeatThread类中,通过调用renew方法实现续租,如下代码所示,方法注释已说明是Restfult请求来实现的,对应Eureka server的返回信息httpResponse,除了检查返回码是否等于200就没有任何作用了,想想也是如此,30秒一次的心跳,不论是请求还是响应都应该尽量简洁,降低服务器和网络的压力:
/**
* Renew with the eureka service by making the appropriate REST call
*/
boolean renew() {
EurekaHttpResponse<InstanceInfo> httpResponse;
try {
//发Restful请求,即心跳
httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
logger.debug("{} - Heartbeat status: {}", PREFIX + appPathIdentifier, httpResponse.getStatusCode());
//404错误会触发注册逻辑
if (httpResponse.getStatusCode() == 404) {
REREGISTER_COUNTER.increment();
logger.info("{} - Re-registering apps/{}", PREFIX + appPathIdentifier, instanceInfo.getAppName());
return register();
}
//返回码200表示心跳成功
return httpResponse.getStatusCode() == 200;
} catch (Throwable e) {
logger.error("{} - was unable to send heartbeat!", PREFIX + appPathIdentifier, e);
return false;
}
}
@Override
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(final String appName,
final String id,
final InstanceInfo info,
final InstanceStatus overriddenStatus) {
return execute(new RequestExecutor<InstanceInfo>() {
@Override
public EurekaHttpResponse<InstanceInfo> execute(EurekaHttpClient delegate) {
//网络处理委托给代理类完成
return delegate.sendHeartBeat(appName, id, info, overriddenStatus);
}
@Override
public RequestType getRequestType() {
//请求类型为心跳
return RequestType.SendHeartBeat;
}
});
}
@Override
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus) {
String urlPath = "apps/" + appName + '/' + id;
ClientResponse response = null;
try {
//请求参数有两个:Eureka client自身状态、自身关键信息(状态、元数据等)最后一次变化的时间
WebResource webResource = jerseyClient.resource(serviceUrl)
.path(urlPath)
.queryParam("status", info.getStatus().toString())
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString());
if (overriddenStatus != null) {
webResource = webResource.queryParam("overriddenstatus", overriddenStatus.name());
}
Builder requestBuilder = webResource.getRequestBuilder();
addExtraHeaders(requestBuilder);
//注意:这里不是POST,也不是GET,而是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));
}
return eurekaResponseBuilder.build();
} finally {
if (logger.isDebugEnabled()) {
logger.debug("Jersey HTTP PUT {}/{}; statusCode={}", serviceUrl, urlPath, response == null ? "N/A" : response.getStatus());
}
if (response != null) {
response.close();
}
}
}
至此,Eureka client向服务续租的源码就分析完毕了,过程相对简单,DiscoveryClient、TimedSupervisorTask、JerseyApplicationClient等实例各司其职,定时发送PUT请求到Eureka server;
文章浏览阅读844次。今天大周给大家分享几个短视频自媒体神器,用好了可以每天轻松200多,话不多说,直接上干货。一、剪映一款新手入门的剪辑神器,界面简洁,一学就会,能满足你的各种剪辑要求。二、西瓜视频在西瓜视频上发布内容,有播放就有收益,播放单价高,没有新手期,注册账号完成实名后可以直接发布内容。三、水印宝一款能去除视频水印的神器,腾讯视频、爱奇艺、优酷等软件下载的视频是有水印的,创作时不去除是会对作品有影响的,用软件直接去除就可以了。四、bigshot可以帮你制作一个炫酷的片头吸引粉丝用户的眼球,还有各种海量的_九天自媒体神器
文章浏览阅读1.4k次。会议:2020 NIPS单位:韩国KAKAO作者:Jungil Kong, Jaehyeon Kim文章主页开源代码文章目录abstractHiFi-GAN生成器结构MSD: multi-scale discriminatorMPD:multi-period discriminator目标函数experimentsablation studyunseen speaker的泛化abstractmotivation:在推理时间 & 生成高保真音质方面均作出改进观点:modeling _hifi-gan: generative adversarial networks for efficient and high fidelity sp
文章浏览阅读1.8w次,点赞48次,收藏185次。用栈实现回文字符串的判断栈是一种后进先出的数据结构,它只能在一段进行插入和删除操作。例如一个字符串"12321",像这种 ,无论正读反读均相同的字符序列,就叫做回文字符串。首先,我们需要读取这行字符串,并求出字符串的长度。 char a[101]; int len; gets(a); len=strlen(a);如果一个字符串是回文的话,那么它必须是中间对称的,我们需要求中点,即: mid=len/2-1;接下来将会涉及到栈的应用;我们先将mid之前的字符全部入栈。因为这里的栈是用_用栈判断字符串是否为回文
文章浏览阅读1.9k次,点赞2次,收藏7次。1.说下volatile吧,了解多少说多少?volatile是JVM(Java Memory Model)中用于保证可见性和有序性的轻量级同步机制。它主要是有两个作用,一是保证被修饰共享变量的可见性,也就是多个线程操作读写时,能被其他线程感知到,在读取变量时会强制将主内存中的变量值读取到自己的工作内存中,写入变量时又会强制自己的新值刷新回主内存;另外一个重要作用在于阻止指令重排序。我们所熟知的双检测单例中,instance必须要用volatile修饰,原因是new SingleTon时,一般说有三个步骤
文章浏览阅读71次。Exchange Server 2013部署系列之一:部署环境介绍源地址:http://543925535.blog.51cto.com/639838/d-6==========================================================================Exchange Server 2013的最低部署要求的Windows Serve...
文章浏览阅读418次,点赞4次,收藏7次。无线帧结构、LTE信道及协议栈分析(物理层)、PCM的主要步骤
文章浏览阅读1.8k次。一、SSL协议加密方式SSL协议即用到了对称加密也用到了非对称加密(公钥加密),在建立传输链路时,SSL首先对对称加密的密钥使用公钥进行非对称加密,链路建立好之后,SSL对传输内容使用对称加密。1.对称加密速度高,可加密内容较大,用来加密会话过程中的消息。2.公钥加密加密速度较慢,但能提供更好的身份认证技术,用来加密对称加密的密钥。单向认证Https在建立Socket连接之前,需要进行握手,具体过..._httos″81278 ″osh
文章浏览阅读3.2k次,点赞2次,收藏4次。通过Zadig给蓝牙适配器安装驱动后,无法恢复的解决办法问题描述蓝牙适配器型号是CSR 8510 A10, 在WIN10里可识别为蓝牙适配器。用Zadig给蓝牙适配器安装WinUSB驱动后,蓝牙适配器无法被Win10正常识别,回退驱动是灰色,删除卸载设备和驱动、重启电脑都没有用。解决办法进入设备管理器找到通用串行总线设备里的CSR8510 A10(如果不在这里你就一个个找csr开头的设备,然后通过蓝牙适配器的插拔,定位到是不是你选的驱动)右击选择更新驱动程序选择浏览我的计_csr8510 a10蓝牙驱动
文章浏览阅读2.5k次。http://blog.csdn.net/scy411082514/article/details/7543929OSM作为开源地图,原始地图数据是完全开发的(并且更新速度很快),获取地图数据的方法可非常多。1、openstreetmap.org 网站本身提供地图数据的下载服务(范围不能过大),使用也很方便,点击地图上端的“输出”,然后选择范围和输出格式即可。2、Kos_open street map 没有建筑层数
文章浏览阅读2.8k次,点赞20次,收藏63次。刚开始学python,选了这个题目,把代码放上来留念,没有用到很流行的框架,所以代码量挺大GUI用wxpython写的# _*_ coding: UTF-8 _*_import osimport reimport requestsimport sysimport wximport tracebackfrom datetime import datetimefrom dateti..._python 微博数据分析
文章浏览阅读3.5k次,点赞2次,收藏12次。分享嘉宾:郑东博士快手 推荐算法技术总监编辑整理:于洋出品平台:DataFunTalk导读:快手是中国领先的短视频和直播社区,拥有超过3亿的DAU和丰富的社交数据。快手秉承的价值观是真实..._快手 融合公式
文章浏览阅读8k次,点赞17次,收藏77次。由磁场数据和加速度数据计算初始姿态角_ros2 角速度和加速度计算姿态角