Su的技术博客

  • 首页
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • Other
  • 工具
  • 打赏
  • 关于
  1. 首页
  2. Java
  3. 正文
                           

【原创】Eureka源码之二:服务注册

2020-01-18 46点热度 0人点赞 0条评论

 

EurekaClient在启动时会进行一系列初始化操作,本篇文章主要解析EurekaClient端向EurekaServer端发起注册请求的具体过程,具体分为EurekaClient端发送请求和EurekaServer端接收请求。在较新的版本看到代码进行了优化,所以还是以某一版本为准进行剖析。这里是1.X版本最新版本1.9.15。

 

〓Eureka Client发出注册请求
// DiscoveryClient构造器中:
if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
//配置了开启注册和强制注册初始化时,则会立马调用注册方法
    try {
        if (!register() ) {
            throw new IllegalStateException("Registration error at startup. Invalid server response.");
        }
    } catch (Throwable th) {
        logger.error("Registration error at startup: {}", th.getMessage());
        throw new IllegalStateException(th);
    }
}

-----------------------------------
// 实例信息复制器初始化,并且启动。
instanceInfoReplicator = new InstanceInfoReplicator(
        this,
        instanceInfo,
        clientConfig.getInstanceInfoReplicationIntervalSeconds(),
        2); // burstSize
instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
// InstanceInfoReplicator.java实现了RUNNABLE,接着看start方法
public void start(int initialDelayMs) {
    if (started.compareAndSet(false, true)) {
        instanceInfo.setIsDirty();  // for initial register
        // 30秒后执行当前对象任务
        Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
        scheduledPeriodicRef.set(next);
    }
}

public void run() {
    try {
        // 刷新实例信息
        discoveryClient.refreshInstanceInfo();
        // 判断实例信息是否发生改变
        // isInstanceInfoDirty默认为false,实例信息发生改变时会被设为true
        // 被设为ture,则dirtyTimestamp不为null,则发起注册请求
        Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
        if (dirtyTimestamp != null) {
            // 注册
            discoveryClient.register();
            instanceInfo.unsetIsDirty(dirtyTimestamp);
        }
    } catch (Throwable t) {
        logger.warn("There was a problem with the instance info replicator", t);
    } finally {
        // 40秒后执行
        Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
        scheduledPeriodicRef.set(next);
    }
}

------------------------------------
 /**
 * 通过REST调用注册eureka服务
 */
boolean register() throws Throwable {
    logger.info(PREFIX + "{}: registering service...", appPathIdentifier);
    EurekaHttpResponse<Void> httpResponse;
    try {
        httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
    } catch (Exception e) {
        logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e);
        throw e;
    }
    if (logger.isInfoEnabled()) {
        logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode());
    }
    // 根据响应状态码204判断是否注册成功
    return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}
Eureka Client启动时会进行注册:
①根据配置是否立即进行注册请求;
②启动实例信息复制器时会延迟30秒进行注册操作,之后每隔40秒延迟之后判断实例信息是否改变而继续执行。

 

〓Eureka Server接收注册请求
// DiscoveryClient构造器中:
if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
//配置了开启注册和强制注册初始化时,则会立马调用注册方法
    try {
        if (!register() ) {
            throw new IllegalStateException("Registration error at startup. Invalid server response.");
        }
    } catch (Throwable th) {
        logger.error("Registration error at startup: {}", th.getMessage());
        throw new IllegalStateException(th);
    }
}

-----------------------------------
// 实例信息复制器初始化,并且启动。
instanceInfoReplicator = new InstanceInfoReplicator(
        this,
        instanceInfo,
        clientConfig.getInstanceInfoReplicationIntervalSeconds(),
        2); // burstSize
instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
// InstanceInfoReplicator.java实现了RUNNABLE,接着看start方法
public void start(int initialDelayMs) {
    if (started.compareAndSet(false, true)) {
        instanceInfo.setIsDirty();  // for initial register
        // 30秒后执行当前对象任务
        Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
        scheduledPeriodicRef.set(next);
    }
}

public void run() {
    try {
        // 刷新实例信息
        discoveryClient.refreshInstanceInfo();
        // 判断实例信息是否发生改变
        // isInstanceInfoDirty默认为false,实例信息发生改变时会被设为true
        // 被设为ture,则dirtyTimestamp不为null,则发起注册请求
        Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
        if (dirtyTimestamp != null) {
            // 注册
            discoveryClient.register();
            instanceInfo.unsetIsDirty(dirtyTimestamp);
        }
    } catch (Throwable t) {
        logger.warn("There was a problem with the instance info replicator", t);
    } finally {
        // 40秒后执行
        Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
        scheduledPeriodicRef.set(next);
    }
}

------------------------------------
 /**
 * 通过REST调用注册eureka服务
 */
boolean register() throws Throwable {
    logger.info(PREFIX + "{}: registering service...", appPathIdentifier);
    EurekaHttpResponse<Void> httpResponse;
    try {
        httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
    } catch (Exception e) {
        logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e);
        throw e;
    }
    if (logger.isInfoEnabled()) {
        logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode());
    }
    // 根据响应状态码204判断是否注册成功
    return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}
总结

 

■Eureka Client:
1)注册1:DisoverClient构造器里会根据是否开启立即调用注册Eureka Server接口进行注册;
2)注册2:实例信息复制器启动时会使用定时调度30秒延迟调用注册方法,如果实例信息发生改变,则之后会每隔40秒进行重新注册;
3)注册方式:使用Jersey HTTP向Eureka Server发起注册请求。
■Eureka Server:
1)启动:EurekaBootStrap启动入口,继承ServletContextListener。核心类:PeerAwareInstanceRegistryImpl;
2)Eureka Server注册逻辑:服务端本地缓存(队列)进行处理注册,比如:状态的更新、添加到近期变化队列等;
3)复制:集群环境下,节点之间需要进行注册信息的同步。除了本身节点,将会复制注册信息到其它对等节点,最后同样是使用Jersey进行请求同步注册。
 

本文仅供学习!所有权归属原作者。侵删!文章来源: 搬运工来架构

标签: 原创 开源框架 源码 eureka 注册中心
最后更新:2023-02-25

Cocodroid

专注Java后端,分享技术。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

最新 热点 推荐
最新 热点 推荐
殷浩详解DDD 第四讲:领域层设计规范 既生@Resource,何生@Autowired? Go整洁架构实践 接口优化的常见方案实战总结 QQ音乐高可用架构体系 构建一个布隆过滤器 —— Building a Bloom filter
殷浩详解DDD 第四讲:领域层设计规范Redis为什么这么快?构建一个布隆过滤器 —— Building a Bloom filterQQ音乐高可用架构体系接口优化的常见方案实战总结Go整洁架构实践
笔记 | 面试官问我高并发的问题:并发编程的三大挑战 【视频】如何写高效内存Java代码——How to Write Memory-Efficient Java Code 如何让Java编译器帮你写代码 殷浩详解DDD 第四讲:领域层设计规范 笔记 | JVM内存区域结构:一计两栈一堆一区 Eureka源码剖析之三:服务拉取

@Autowired (1) @Resource (1) API网关 (1) ddd (6) DP (1) ElasticSearch (1) eureka (7) go (1) HTTP (1) IDEA (1) iOS (1) Java (8) JSR (1) QQ音乐 (1) repository (1) Spring (1) SQL优化 (1) 代理 (1) 依赖注入 (1) 同城双活 (1) 垃圾回收 (1) 定时任务 (1) 容灾 (1) 布隆过滤器 (1) 异地双活 (1) 接口优化 (1) 故障转移 (1) 数据库 (2) 整洁架构 (1) 文件网关 (1) 方案 (2) 服务续约 (1) 注册中心 (7) 流水账 (1) 流量 (1) 第五 (1) 线上案例 (1) 线上问题 (2) 缓存 (1) 缓存击穿 (1) 编译 (3) 网络 (3) 聊聊 (1) 订单 (1) 设计规范 (1) 详解 (1) 连接池 (1) 限流 (1) 领域驱动设计 (4) 高可用 (1)

COPYRIGHT © 2014-2023 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2