Eureka Client启动流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ExampleEurekaClient {
public static void main(String[] args) throws UnknownHostException {
ExampleEurekaClient sampleClient = new ExampleEurekaClient();

// 这个new MyDataCenterInstanceConfig(),其实主要就是读取eureka-client.properties,然后构建一个服务实例配置
ApplicationInfoManager applicationInfoManager = initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
// 这个new DefaultEurekaClient(),其实就是读取eureka-client.properties构造一个eureka客户端配置
// 基于接口对外提供eureka-client的配置读取
EurekaClient client = initializeEurekaClient(applicationInfoManager, new DefaultEurekaClientConfig());

// 用eureka客户端向eureka server发送请求
sampleClient.sendRequestToServiceUsingEureka(client);

// 关闭eureka客户端
eurekaClient.shutdown();
}

// 这里就是根据服务实例配置,初始化服务信息管理器
private static synchronized ApplicationInfoManager initializeApplicationInfoManager(EurekaInstanceConfig instanceConfig) {
if (applicationInfoManager == null) {
// 1. 根据服务实例配置,构造一个服务实例
InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();
// 2. 根据服务实例和配置,构造一个应用信息管理器
applicationInfoManager = new ApplicationInfoManager(instanceConfig, instanceInfo);
}

return applicationInfoManager;
}

// 根据应用信息管理器和eureka-client配置,构造出EurekaClient
private static synchronized EurekaClient initializeEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig clientConfig) {
if (eurekaClient == null) {
eurekaClient = new DiscoveryClient(applicationInfoManager, clientConfig);
}

return eurekaClient;
}
}

其实这部分已经在上篇文章剖析过了,这里直接出总结

03-eureka client启动流程

Eureka Client是如何进行服务注册的

  • 在eureka-client实例化的最后一步,启动了一个实例信息复制器,默认40秒之后开始执行,这个定时任务逻辑如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void start(int initialDelayMs) {
if (started.compareAndSet(false, true)) {
// 先将代表自己的这个服务实例状态设置为dirty
// 其实,标记为dirty就是为了在下一次服务心跳时将实例信息发给eureka server
instanceInfo.setIsDirty(); // for initial register
Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}

public void run() {
try {
// 先刷新一下实例信息
discoveryClient.refreshInstanceInfo();

Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
if (dirtyTimestamp != null) {
// 这里才是真正的服务注册
// 这里其实就是调用网络通信组件的服务注册客户端向eureka server的POST /apps 接口发起服务注册
discoveryClient.register();
// 注册完成了,就不需要在心跳里发送这个服务实例了
instanceInfo.unsetIsDirty(dirtyTimestamp);
}
} catch (Throwable t) {
logger.warn("There was a problem with the instance info replicator", t);
} finally {
// 这个replicationIntervalSeconds 默认是40秒
// 也就是说eureka client启动时,延迟40秒才进行服务注册,这点儿非常坑,在Spring Cloud Netflix中已被修复(马上注册)
Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}

Eureka Server是如何完成服务注册的

  • 上一步客户端发起服务注册后,ApplicationResource#addInstance 会接收到请求,最终将请求转给PeerAwareInstanceRegistry.register
  • 进行注册
    • 将请求送上来的实例信息放到自己的服务注册表中ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry
    • 将服务实例放到最近注册队列(recentRegisteredQueue)中去
    • 将服务实例放到最近变更队列(recentlyChangedQueue)中去
    • 过期ResponseCache
  • 同步注册到其他节点

总结

eureka的服务注册的流程

Comments