注册中心 Eureka 源码解析 —— 应用实例注册发现(一)之注册

本文详细解析了 Eureka-Client 如何向 Eureka-Server 注册应用实例,包括实例信息复制器、刷新信息、发起注册等步骤,并介绍了 Eureka-Server 接收注册的过程,涉及租约、应用实例状态管理和自我保护机制。
摘要由CSDN通过智能技术生成

摘要: 原创出处 http://www.iocoder.cn/Eureka/instance-registry-register/ 「芋道源码」欢迎转载,保留摘要,谢谢!

本文主要基于 Eureka 1.8.X 版本


������关注微信公众号:【芋道源码】有福利:
1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
4. 新的源码解析文章实时收到通知。每周更新一篇左右
5. 认真的源码交流微信群。


1. 概述

本文主要分享 Eureka-Client 向 Eureka-Server 注册应用实例的过程

FROM http://techshow.ctrip.com/archives/1699.html》”>《深度剖析服务发现组件Netflix Eureka》 二次编辑

  • 蓝框部分,为本文重点。
  • 蓝框部分,Eureka-Server 集群间复制注册的应用实例信息,不在本文内容范畴。

推荐 Spring Cloud 书籍

推荐 Spring Cloud 视频

2. Eureka-Client 发起注册

Eureka-Client 向 Eureka-Server 发起注册应用实例需要符合如下条件:

  • 配置 eureka.registration.enabled = true,Eureka-Client 向 Eureka-Server 发起注册应用实例的开关
  • InstanceInfo 在 Eureka-Client 和 Eureka-Server 数据不一致。

每次 InstanceInfo 发生属性变化时,标记 isInstanceInfoDirty 属性为 true,表示 InstanceInfo 在 Eureka-Client 和 Eureka-Server 数据不一致,需要注册。另外,InstanceInfo 刚被创建时,在 Eureka-Server 不存在,也会被注册。

当符合条件时,InstanceInfo 不会立即向 Eureka-Server 注册,而是后台线程定时注册。

当 InstanceInfo 的状态( status ) 属性发生变化时,并且配置 eureka.shouldOnDemandUpdateStatusChange = true 时,立即向 Eureka-Server 注册。因为状态属性非常重要,一般情况下建议开启,当然默认情况也是开启的

Let’s Go。让我们看看代码的实现。

2.1 应用实例信息复制器

// DiscoveryClient.java
public class DiscoveryClient implements EurekaClient {
   

    /**
     * 应用实例状态变更监听器
     */
    private ApplicationInfoManager.StatusChangeListener statusChangeListener;
    /**
     * 应用实例信息复制器
     */
    private InstanceInfoReplicator instanceInfoReplicator;

    private void initScheduledTasks() {
        // ... 省略无关代码

        if (clientConfig.shouldRegisterWithEureka()) {

            // ... 省略无关代码

            // 创建 应用实例信息复制器
            // InstanceInfo replicator
            instanceInfoReplicator = new InstanceInfoReplicator(
                    this,
                    instanceInfo,
                    clientConfig.getInstanceInfoReplicationIntervalSeconds(),
                    2); // burstSize

            // 创建 应用实例状态变更监听器
            statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
                @Override
                public String getId() {
                    return "statusChangeListener";
                }

                @Override
                public void notify(StatusChangeEvent statusChangeEvent) {
                    if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
                            InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
                        // log at warn level if DOWN was involved
                        logger.warn("Saw local status change event {}", statusChangeEvent);
                    } else {
                        logger.info("Saw local status change event {}", statusChangeEvent);
                    }
                    instanceInfoReplicator.onDemandUpdate();
                }
            };

            // 注册 应用实例状态变更监听器
            if (clientConfig.shouldOnDemandUpdateStatusChange()) {
                applicationInfoManager.registerStatusChangeListener(statusChangeListener);
            }

            // 开启 应用实例信息复制器
            instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
        }

    }

}
  • com.netflix.discovery.InstanceInfoReplicator,应用实例信息复制器。

    • 调用 InstanceInfoReplicator#start(...) 方法,开启应用实例信息复制器。实现代码如下:

      // InstanceInfoReplicator.java
      class InstanceInfoReplicator implements Runnable {
      
          private static final Logger logger = LoggerFactory.getLogger(InstanceInfoReplicator.class);
      
          private final DiscoveryClient discoveryClient;
          /**
           * 应用实例信息
           */
          private final InstanceInfo instanceInfo;
          /**
           * 定时执行频率,单位:秒
           */
          private final int replicationIntervalSeconds;
          /**
           * 定时执行器
           */
          private final ScheduledExecutorService scheduler;
          /**
           * 定时执行任务的 Future
           */
          private final AtomicReference<Future> scheduledPeriodicRef;
          /**
           * 是否开启调度
           */
          private final AtomicBoolean started;
      
          private final RateLimiter rateLimiter; // 限流相关,跳过
          private final int burstSize; // 限流相关,跳过
          private final int allowedRatePerMinute; // 限流相关,跳过
      
          InstanceInfoReplicator(DiscoveryClient discoveryClient, InstanceInfo instanceInfo, int replicationIntervalSeconds, int burstSize) {
              this.discoveryClient = discoveryClient;
              this.instanceInfo = instanceInfo;
              this.scheduler = Executors.newScheduledThreadPool(1,
                      new ThreadFactoryBuilder()
                              .setNameFormat("DiscoveryClient-InstanceInfoReplicator-%d")
                              .setDaemon(true)
                              .build());
      
              this.scheduledPeriodicRef = new AtomicReference<Future>();
      
              this.started = new AtomicBoolean(false);
              this.rateLimiter = new RateLimiter(TimeUnit.MINUTES);
              this.replicationIntervalSeconds = replicationIntervalSeconds;
              this.burstSize = burstSize;
      
              this.allowedRatePerMinute = 60 * this.burstSize / this.replicationIntervalSeconds;
              logger.info("InstanceInfoReplicator onDemand update allowed rate per min is {}", allowedRatePerMinute);
          }
      
          public void start(int initialDelayMs) {
              if (started.compareAndSet(false, true)) {
                  // 设置 应用实例信息 数据不一致
                  instanceInfo.setIsDirty();  // for initial register
                  // 提交任务,并设置该任务的 Future
                  Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
                  scheduledPeriodicRef.set(next);
              }
          }
      
          // ... 省略无关方法
      }
      
      // InstanceInfo.java
      private volatile boolean isInstanceInfoDirty = false;
      
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值