Su的技术博客

  • 首页
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • AI
  • Other
  • 工具
  • 打赏
  • 关于
路很长,又很短
  1. 首页
  2. Java
  3. 正文
                           

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

2020-01-18 187点热度 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进行请求同步注册。
 

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

更多文章:

  1. Eureka源码剖析之一:初始化-启动
  2. Eureka源码剖析之三:服务拉取
  3. Eureka源码剖析之四:服务续约
  4. Eureka源码剖析之五:服务下线
  5. 殷浩详解DDD系列 第一讲 - Domain Primitive
  6. 浅析设计模式5 -- 责任链模式
  7. Eureka 客户端配置注册地址为什么要加eureka做后缀?
  8. 殷浩详解DDD 第四讲:领域层设计规范
标签: 原创 开源框架 源码 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
取消回复

最新 热点 推荐
最新 热点 推荐
单体分层应用架构剖析 MySQL事务死锁问题排查 浅谈DDD中的聚合 高并发场景下JVM调优实践之路 ChatGPT的探索与实践 生产环境的CMS垃圾回收,一定要这样配置参数
Log4j框架疯狂写日志,导致磁盘打满问题排查高并发场景下JVM调优实践之路4.架构风格 vs. 架构模式 vs. 设计模式(译)5.单体架构(译)6.分层架构(译)ChatGPT的探索与实践
实现一个状态机引擎,教你看清DSL的本质 超实用的IDEA插件推荐!百万级下载量 Cache——对于缓存你应该知道的都在这张图里 1.软件架构编年史(译) 殷浩详解DDD系列 第一讲 - Domain Primitive 做好技术负责人的4个关键特质

AIGC (1) BASE (1) bigkey (1) CAP (1) codeium (2) Copilot (2) hotkey (1) inject (1) jar包 (1) mvc (1) OOP (1) UML (1) vivo (2) 事务隔离级别 (1) 人工智能 (2) 代码质量 (1) 低耦合 (1) 依赖倒置原则 (1) 六边形架构 (1) 分层架构 (3) 分布式事务 (1) 分页 (1) 单体架构 (2) 可复用性 (1) 可读性 (1) 合同 (1) 后端开发 (1) 命名 (1) 四色建模法 (1) 垃圾回收器 (1) 开源 (1) 性能调优 (4) 智能助手 (1) 架构模式 (1) 架构设计 (4) 架构风格 (1) 模块 (1) 死锁 (1) 物流 (1) 系统架构 (4) 缓存穿透 (1) 缓存雪崩 (1) 编程助手 (3) 编程技能 (1) 编程语言 (2) 聚合 (1) 软件工程师 (1) 软件架构 (2) 驱动升级 (1) 高内聚 (1)

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

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2