Eureka Client的初始化

Eureka Client与应用程序相结合,提供了服务注册、续期、获取注册表等功能。 相比于Eureka Server,因为它是无状态的,因此实现上也简单很多

我们一起来看看,源码中Eureka Client是如何启动的?

一 核心类DiscoveryClient

来看源码中注释:

该类是与Eureka Server交互的工具。Eureka客户端负责:

a)在Eureka服务器上注册实例

b)与Eureka服务器续签租约

c)在关闭期间从Eureka服务器取消租约

d)查询在Eureka Server上注册的服务/实例列表

Eureka Client需要一个配置好的Eureka Server url列表 来与之对话。这些java.net.url通常是不会更改的amazon弹性ip。在与某个Eureka Server交互失败时,都将故障转移到列表中其他的Eureka Server url。

如下Eureka Client的配置,Eureka Server url就是指serviceUrl,当其中某个地址不通时,将使用其他url,即故障转移

yaml 复制代码
# eureka client配置示例
eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    serviceUrl:
      # 当Eureka Server集群部署时,此处应配置多个url
      defaultZone: http://192.168.2.4:8761/eureka/,http://192.168.2.125:8761/eureka/

在DiscoveryClient的构造方法中,完成了Eureka Client的启动。

二、初始化过程

启动过程,其实就是创建一个DiscoveryClient实例的过程。

1.1 DiscoveryClient的构造方法

  • 构造器中,提供了一个创建BackupRegistry子类实例的Provider;

BackupRegistry接口,是在client无法从任何eureka Server获取注册表时,提供一个配置的注册表。默认采用空实现。

  • ApplicationInfoManager:管理当前应用节点自身信息,如ipAddr、port、status等,这些信息用于注册,或被其他服务发现;
  • EurekaClientConfig:eureka客户端向eureka服务器注册实例所需的配置信息 。大多数必需的信息由默认配置DefaultEurekaClientConfig提供,用户只需要提供eureka服务器服务url

2.2 创建空注册表

java 复制代码
private final AtomicReference<Applications> localRegionApps = new AtomicReference<Applications>();
// 创建空应用集
localRegionApps.set(new Applications());

Applications是对eureka server返回的注册表的封装,关键属性有:应用队列、注册表。 而Application用于保存某个应用程序的节点列表,有以下属性。 再来看InstanceInfo类,是对某个应用集群某个节点的封装 ,关键属性是节点的网络地址:instanceId、appName、ipAddr和port。

2.3 保存serviceUrl和创建Transport

java 复制代码
// 对serviceUrl的封装
remoteRegionsToFetch = new AtomicReference<String>(clientConfig.fetchRegistryForRemoteRegions());  
remoteRegionsRef = new AtomicReference<>(remoteRegionsToFetch.get() == null ? null : remoteRegionsToFetch.get().split(","));

EurekaTransport是DiscoveryClient中的内部类,用于创建和持有与Eureka Server交互的HttpClient:分别创建了用于fetch、pull的Client。

java 复制代码
eurekaTransport = new EurekaTransport();  
scheduleServerEndpointTask(eurekaTransport, args);

TransportClientFactories有两个实现,默认使用Jersey1TransportClientFactories

2.4 创建线程池

当shouldRegisterWithEureka、shouldFetchRegistry都为false时,会提前return。否则,创建3个线程池。 将在后面看到对它们的使用。

java 复制代码
// 调用线程池
private final ScheduledExecutorService scheduler;
// 执行注册、心跳请求
private final ThreadPoolExecutor heartbeatExecutor;
// 刷新Eureka client端缓存的注册表
private final ThreadPoolExecutor cacheRefreshExecutor;

2.5 从Eureka Server拉取注册表

java 复制代码
// 从Eureka Server拉取注册表
if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) {
  // 失败时通过BackupRegistry获取
  fetchRegistryFromBackup();
}

注意,源码中"是否拉取注册表",配置名是shouldFetchRegistry,在springboot整合包中叫fetchRegistry,默认为true。

来看fetchRegistry(),在第一次获取注册表时为全量拉取;之后只获取增量。

java 复制代码
// 简化后代码
if (全量拉取){
	getAndStoreFullRegistry();
} else {
	getAndUpdateDelta(applications);
}

2.6 启动周期任务

调用DiscoveryClient.initScheduledTasks(),创建了刷新注册表、续租、节点信息更新同步任务。

  • 如果shouldFetchRegistry=true,则添加周期刷新注册表任务
java 复制代码
// 周期刷新注册表
scheduler.schedule(
        new TimedSupervisorTask(
                "cacheRefresh",
                scheduler,
                cacheRefreshExecutor,
                registryFetchIntervalSeconds,
                TimeUnit.SECONDS,
                expBackOffBound,
                new CacheRefreshThread()
        ),
        registryFetchIntervalSeconds, TimeUnit.SECONDS);
  • 如果shouldRegisterWithEureka为true,则创建心跳周期任务
java 复制代码
// Heartbeat timer
scheduler.schedule(
        new TimedSupervisorTask(
                "heartbeat",
                scheduler,
                heartbeatExecutor,
                renewalIntervalInSecs,
                TimeUnit.SECONDS,
                expBackOffBound,
                new HeartbeatThread()
        ),
        renewalIntervalInSecs, TimeUnit.SECONDS);
  • 注册StatusChangeListener 当配置shouldOnDemandUpdateStatusChange=true时,将在节点状态变为DOWN时,立即同步节点信息给Eureka。

  • 启动节点信息更新同步任务 创建 InstanceInfoReplicator实例,用于更新该节点的InstanceInfo(如元数据、节点状态等),将其同步到Eureka server。

    • 当节点信息发生变化时,设置InstanceInfo.isInstanceInfoDirty=true和lastDirtyTimestamp;
    • 使用仅有1个线程的ScheduledThreadPool,来周期检查isInstanceInfoDirty标志
    • 节点信息更新同步,是通过发起一次注册来实现;

2.7 启动监控任务

三、总结

  • DiscoveryClient是核心资源持有者,包括应用集、注册表、线程池、Http客户端等;
  • Eureka Client的启动过程,就是创建DiscoveryClient示例的过程;
  • 启动时,初始化一些全局资源,从Eureka初次拉取注册表,启动刷新注册表本地缓存、续租、节点信息变更同步这3个周期任务;

在随后的文章中,将进一步熟悉客户端注册、续租等的实现。

相关推荐
浮游本尊1 小时前
Java学习第22天 - 云原生与容器化
java
稻草人22223 小时前
java Excel 导出 ,如何实现八倍效率优化,以及代码分层,方法封装
后端·架构
渣哥3 小时前
原来 Java 里线程安全集合有这么多种
java
间彧3 小时前
Spring Boot集成Spring Security完整指南
java
间彧3 小时前
Spring Secutiy基本原理及工作流程
java
数据智能老司机4 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
Java水解4 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
数据智能老司机5 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
洛小豆6 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学7 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端