概述
目录
- 前言
- 一、Eureka流程图
- 1. 注册Register:客户端向服务端注册
- 2. 续约Renew:客户端会定时(默认30s一次)向服务端发送自己的主机信息,并更新服务端列
- 3. 下线Cancel:服务下架
- 4. 获取注册表Get Registry:获取服务端中,客户端注册信息列表
- 5. 同步复制Replicate:Server集群之间同步注册信息列表
- 二、Eureka Client源码解析
- 1、源码入口
- 2、Client的配置类
- 2.1、进入EurekaClientAutoConfiguration类
- 2.2、在EurekaClientAutoConfiguration类中初始化了一些关键Bean
- 2.3、重点关注EurekaClientAutoConfiguration类中的RefreshableEurekaClientConfiguration类
- 3、从Eureka Server中拉取注册信息表
- 4、向Eureka Server中注册
- 5、定时任务
- 5.1 定时任务:更新客户端注册表
- 5.2 定时任务:定时心跳续租
- 5.3 定时任务:检查更新续约信息
- 1、使用了定时的线程池
- 2、start()后将执行run()方法
- 3、跟进discoveryClient.refreshInstanceInfo();方法中
- 4、再次回到run()方法
- 5、检查更新续约信息流程图
- 6、服务下线
- 1、首先执行cancelScheduledTasks() 取消所有定时任务;
- 2、依次停止了 定时检测更新配置文件、定时心跳、定时更新注册表 以及 其他定时任务;
- 3、修改instanceInfo状态为DOWN以及关闭监视器;
- 4、跟进unregister()方法,进行服务下架;
- 5、最终是发送delete请求完成服务下架;
前言
分析eureka源码建议先从client端开始,再进入到server端一、Eureka流程图
图片来源:https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance
图片来源:《Spring Cloud 微服务架构进阶》
从上图可以看出整个Eureka是分为client(客户端)、server(服务端),其中我要对图中的几个关键过程进行简单叙述;
1. 注册Register:客户端向服务端注册
读取自身服务实例配置信息,封装成EurekalnstanceConfig;
从Eureka Server中拉取注册信息表;
2. 续约Renew:客户端会定时(默认30s一次)向服务端发送自己的主机信息,并更新服务端列
3. 下线Cancel:服务下架
4. 获取注册表Get Registry:获取服务端中,客户端注册信息列表
5. 同步复制Replicate:Server集群之间同步注册信息列表
二、Eureka Client源码解析
1、源码入口
Eukeka Client 通过 Starter 的方式引人依赖, Spring Boot 将会为项目使用以下 自动配置类
2、Client的配置类
2.1、进入EurekaClientAutoConfiguration类
重点关注两个注解:
@AutoConfigureBefore:表明在配置3个类之前,先要完成当前类配置才可以(当前类配置在前)
@AutoConfigureAfter:表示如果想让当前配置类起作用,需要先对3个配置类进行配置(当前类配置在后)
值得注意的是在2.1.1中@AutoConfigureAfter这里是3个类,DiscoveryClientOptionalArgsConfiguration是以@Import(DiscoveryClientOptionalArgsConfiguration.class)注入的
2.2、在EurekaClientAutoConfiguration类中初始化了一些关键Bean
// 这个类的作用是将配置文件中以eureka.client为前缀的配置信息进行读取后封装
@Bean
@ConditionalOnMissingBean(value = EurekaClientConfig.class,
search = SearchStrategy.CURRENT)
public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
// 前配置文件中以eureka.client为前缀的信息进行读取并封装
return new EurekaClientConfigBean();
}
// 这个类的作用是将关于eureka实例的配置信息进行读取后封装。
@Bean
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class,search = SearchStrategy.CURRENT)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils,ManagementMetadataProvider managementMetadataProvider) {
String hostname = getProperty("eureka.instance.hostname");
boolean preferIpAddress = Boolean.parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
String ipAddress = getProperty("eureka.instance.ip-address");
boolean isSecurePortEnabled = Boolean.parseBoolean(getProperty("eureka.instance.secure-port-enabled"));
2.3、重点关注EurekaClientAutoConfiguration类中的RefreshableEurekaClientConfiguration类
因为eureka的客户端是在这里创建的
DiscoveryClient Spring Cloud 中用来进行服务发现的顶级接口
3、从Eureka Server中拉取注册信息表
目标是进入DiscoveryClient中的下图方法中
这个方法很长,需要关注的是以下几点:
1、shouldRegisterWithEureka(对应配置eureka.client.register-with-eureka )为 true 表示Eureka Client 将注册到 Eureka Server;
2、shouldFetchRegistry(对应配置为 eureka client.fetch-register)为 true 表示 Eureka Client 将从 Eureka Server中拉取注册表信息;
如果上述的两个配置均为 false 那么 Discovery 的初始化时就直接结束,表示该客户端既不进行服务注册也不进行服务发现。
3、在初始化3个线程池(后续定时任务中会说)后,红框中的方法是去服务端拉取注册信息;
clientConfig.shouldFetchRegistry()上面有提,默认为true,接着进入到fetchRegistry(false)方法:
该方法中Applications在开篇中有解释;
进入getAndStoreFullRegistry()方法:
继续跟进,注意这里要进入AbstractJerseyEurekaHttpClient:
serviceUrl即为server地址;
从Server端拉取注册表使用的是Jersey中的GET请求;
并且在返回200之后,将 Eureka Server 中拉取注册表中所有的服务 例信息
全量拉取将 Eureka Server 中拉取注册表中所有的服务实例信息(封装在 Applications
中),并经过处理后替换掉本地注册表缓存Applications;
值得注意的是:getAndStoreFullRegistry()方法可能会被多个线程同时调用,导致新拉取的注册表被旧的注册表覆盖,产生了脏数据,因为Eureka通过Atomic的对applications的更新版本进行CAS更新,拉取到注册表信息之后对获取到的applications信息进行筛选,只保留状态为UP的服务实例信息
4、向Eureka Server中注册
再次回到DiscoveryClient中,在获取完注册表信息后:
clientConfig.shouldRegisterWithEureka()表示:是否注册到Eureka;
clientConfig.shouldEnforceRegistrationAtInit()表示:在初始化的时候强制进行注册;
进入register() 注册方法:
Eureka Client 会将自身服务实例元数据(封装在 Instancelnfo 中)发送到 Eureka Server 中请求服务注册,当 Eureka Server 返回 NO_CONTENT (204)状态码时,说明服务注册成功。
值得注意的是:这里请注册是PUT方法,并且在调用的是AbstractJerseyEurekaHttpClient的register时eureka使用了装饰器模式,提升了组件的扩展性:
JerseyClient:执行rest请求的工具,eureka有RestTemplate的替换实现方案
统计信息:根据请求类型进行统计,请求时间总计、请求失败次数总计等;
重定向:返回的http code是302则表示要重定向(注册中心迁移?)更换重定向的url再次发起请求,最多重定向10次;
失败重试机制:已经请求失败的server url记录下来下次不再请求;如果失败的url过多(比如全部都失败的情况,可能是客户端网络有问题),超过阀值,则清空失败的url记录,把他们重新当成可用的url ,这里要获取注册中心地址列表,用于重试;
会话:请求失败的url记录多久,永久记录吗?使用session机制如果20分钟没请求过,则重置上面的所有机制,session有效时长20分钟左右(有随机增减)
5、定时任务
- 定时更新客户端注册表
在server注册表中的服务实例信息是动态变化的,为了保持最新一致性,client需求定时从server上拉取注册表信息并更新本地缓存 - 定时心跳续租
服务注册应该是一个持续的过程,client通过定时发送心跳的方式与server进行通信,以维持自己在server注册表上的租约续期 - 定时检查更新续约信息
为了监控client上的信息和状态变化,client设置了一个注册定时器,定时检查应用信息或状态的变化,并在发生变化时向server重新注册,避免在注册表中的本服务实例信息不可用
5.1 定时任务:更新客户端注册表
可以通过过eureka.client.registry-fetch-interval-seconds进行设置,默认30s刷新一次
由TimedSupervisorTask提供实现,TimedSupervisorTask继承了TimerTask,执行定时任务
进入new CacheRefreshThread()中的refreshRegistry()方法
这里又回到了fetchRegistry(boolean forceFullRegistryFetch) 方法,这次走的增量拉取server端的注册表信息,上图代码后续就是说如果发现变化,就打印更新注册表之后的变化
5.2 定时任务:定时心跳续租
可以通过过eureka.instance.lease-renewal-interval-in-seconds进行设置,默认30s刷新一次
由TimedSupervisorTask提供实现,TimedSupervisorTask继承了TimerTask,执行定时任务
注意这里的Status.NOT_FOUND 指的是,发送心跳实际上是将instanceinfo发送到服务端,如果服务端的注册表信息中没有我的这个instanceinfo,就会发生NOT_FOUND,如果状态是NOT_FOUND ,则重新进行注册操作
进入sendHeartBeat()方法中,在向server发送心跳续约请求时,需要关注LastDirtyTimestamp,server接收到这个请求,会对这个字段数值进行比较,详细内容将在server端中做解释
5.3 定时任务:检查更新续约信息
InstanceInfoReplicator类的作用是:更新和复制本地的instanceinfo到远程server,这里要说明一点,client的配置文件是可以动态修改的,这里面会通过定时任务去检查配置文件的修改并同步到server端
1、使用了定时的线程池
2、start()后将执行run()方法
3、跟进discoveryClient.refreshInstanceInfo();方法中
refreshDataCenterInfoIfRequired()主要是为了检查hostname是否发生改变;
refreshLeaseInfoIfRequired(),是为了更新租约信息,重点更进:
1、instanceInfo.getLeaseInfo()是获取当前的续约信息;
2、getLeaseExpirationDurationInSeconds()是在配置文件eureka.instance.lease-renewal-interval-in-seconds:指定客户端多少秒向服务端发一次心跳;
3、getLeaseRenewalIntervalInSeconds()是在配置文件eureka.instance.lease-renewal-interval-in-seconds:指定当前客户端多少秒内没有向服务端发送心跳,则让服务端认为其宕机,踢除掉该服务;
4、instanceInfo.setIsDirty():这个字段代表instanceInfo配置已经被修改了,并记录最新修改的时间戳
4、再次回到run()方法
isDirtyWithTime()方法中校验了isInstanceInfoDirty字段,如果在instanceInfo配置被修改了,在上图中就被修改为了true,就需要重新注册。
也可以说如果把续约信息改掉了,则说明这个instanceinfo对server来说是一个全新的,需要注册。
5、检查更新续约信息流程图
6、服务下线
一般情况下,应用服务在关闭的时候, Eureka Client会主动向 Eureka Server注销自身在注册表中的信息。
源码入口:EurekaClientAutoConfiguration->RefreshableEurekaClientConfiguration
这一段代码在最一开始创建EurekaClient代码中有一个destroyMethod = “shutdown”,跟进这个方法:
1、首先执行cancelScheduledTasks() 取消所有定时任务;
2、依次停止了 定时检测更新配置文件、定时心跳、定时更新注册表 以及 其他定时任务;
3、修改instanceInfo状态为DOWN以及关闭监视器;
4、跟进unregister()方法,进行服务下架;
5、最终是发送delete请求完成服务下架;
服务下线的接口地址为 apps ${APP_NAME} ${INSTANCE_INFO_ID },传递参数为服
务名和服务实例 id, HTTP 方法为 delete
最后
以上就是飞快大炮为你收集整理的SpringCloud源码解析之eureka-client客户端前言一、Eureka流程图二、Eureka Client源码解析的全部内容,希望文章能够帮你解决SpringCloud源码解析之eureka-client客户端前言一、Eureka流程图二、Eureka Client源码解析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复