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个周期任务;

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

相关推荐
天天扭码10 分钟前
五天SpringCloud计划——DAY1之mybatis-plus的使用
java·spring cloud·mybatis
程序猿小柒16 分钟前
leetcode hot100【LeetCode 4.寻找两个正序数组的中位数】java实现
java·算法·leetcode
不爱学习的YY酱1 小时前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
丁总学Java1 小时前
Maven项目打包,com.sun.tools.javac.processing
java·maven
kikyo哎哟喂1 小时前
Java 代理模式详解
java·开发语言·代理模式
duration~1 小时前
SpringAOP模拟实现
java·开发语言
小码ssim1 小时前
IDEA使用tips(LTS✍)
java·ide·intellij-idea
潜洋2 小时前
Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序
java·spring boot·后端
暮志未晚Webgl2 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5
小叶lr3 小时前
idea 配置 leetcode插件 代码模版
java·leetcode·intellij-idea