Eureka 学习笔记5:InstanceRegistry

news2024/9/23 13:18:59

版本 awsVersion = ‘1.11.277’

InstanceRegistry


LeaseManager 接口管理实例的租约信息,提供以下功能:

  1. 注册实例
  2. 取消注册实例
  3. 实例续约
  4. 剔除过期实例
public interface LeaseManager<T> {
    /*
     * 注册实例并续约
     */
    void register(T r, int leaseDuration, boolean isReplication);
    /**
     * 取消注册实例
     */
    boolean cancel(String appName, String id, boolean isReplication);
    /**
     * 续约
     */
    boolean renew(String appName, String id, boolean isReplication);
    /**
     * 剔除过期实例
     */
    void evict();
}

InstanceRegistry 接口即注册表服务,继承 LeaseManager 接口,提供以下功能:

  1. 启动和关闭注册表服务
  2. 更新注册表中实例的状态
  3. 从注册表中获取应用信息和实例信息
  4. 初始化和获取注册表缓存
  5. 租约过期机制和自我保护机制(和 LeaseManager 的 evict() 方法相关)
public interface InstanceRegistry extends LeaseManager<InstanceInfo>, LookupService<String> {

    // ========================
    // 启动和关闭注册表服务
    // ========================

    /**
     * 在PeerAwareInstanceRegistry接口的init()和syncUp()方法调用后被调用
     * 1.更新expectedNumberOfClientsSendingRenews
     *   更新numberOfRenewsPerMinThreshold
     * 2.如果从其他Eureka节点拉取注册表成功并且实例数量大于0
     *   设置peerInstancesTransferEmptyOnStartup为false
     *   和PeerAwareInstanceRegistry接口的shouldAllowAccess()方法相关
     * 3.设置startupTime为当前时间
     * 4.设置自身实例状态为InstanceStatus.UP
     * 5.调用postInit()方法
     *   创建EvictionTask并通过Timer调度定时剔除过期实例
     *   配置evictionIntervalTimerInMs指定剔除过期实例的时间间隔,默认60s
     */
    void openForTraffic(ApplicationInfoManager applicationInfoManager, int count);
    void shutdown();

    // ========================
    // 更新注册表中实例的状态
    // ========================

    @Deprecated
    void storeOverriddenStatusIfRequired(String id, InstanceStatus overriddenStatus);
    /**
     * 更新注册表中实例的overriddenStatus
     */
    void storeOverriddenStatusIfRequired(String appName, String id, InstanceStatus overriddenStatus);
    /**
     * 更新注册表中实例的overriddenStatus和status
     */
    boolean statusUpdate(String appName,
                         String id,
                         InstanceStatus newStatus,
                         String lastDirtyTimestamp,
                         boolean isReplication);
    /**
     * 删除注册表中实例的overriddenStatus并设置status
     */
    boolean deleteStatusOverride(String appName,
                                 String id,
                                 InstanceStatus newStatus,
                                 String lastDirtyTimestamp,
                                 boolean isReplication);
    /**
     * 获取注册表中overriddenStatus集合的快照
     */
    Map<String, InstanceStatus> overriddenInstanceStatusesSnapshot();

    // ========================
    // 注册表 CRUD
    // ========================

    /**
     * 获取本地注册表
     */
    Applications getApplicationsFromLocalRegionOnly();
    /**
     * 根据应用名称从本地注册表或其他region的注册表中获取应用信息
     */
    Application getApplication(String appName, boolean includeRemoteRegion);
    /**
     * 根据应用名称和实例id从本地注册表或其他region的注册表中获取实例信息
     */
    InstanceInfo getInstanceByAppAndId(String appName, String id);
    /**
     * 根据应用名称和实例id从本地注册表或其他region的注册表中获取实例信息
     */
    InstanceInfo getInstanceByAppAndId(String appName, String id, boolean includeRemoteRegions);
    /**
     * 清空注册表
     */
    void clearRegistry();

    // ========================
    // 注册表缓存
    // ========================

    /**
     * 初始化注册表缓存ResponseCacheImpl
     */
    void initializedResponseCache();
    /**
     * 获取注册表缓存ResponseCacheImpl
     */
    ResponseCache getResponseCache();

    // ========================
    // 租约过期机制&自我保护机制
    // ========================

    /**
     * 获取上一分钟收到的续约(renew)请求数
     */
    long getNumOfRenewsInLastMin();
    /**
     * 获取每一分钟续约(renew)请求数的阈值
     * 如果上一分钟收到的续约请求数小于阈值,开启自我保护机制
     * 计算方式:实例数量 * (60 / 续约间隔时间)* 续约百分比阈值0.85
     * this.expectedNumberOfClientsSendingRenews * 
     *     (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds()) *
     *     serverConfig.getRenewalPercentThreshold())
     */
    int getNumOfRenewsPerMinThreshold();
    /**
     * 是否启用租约过期机制
     */
    boolean isLeaseExpirationEnabled();
    /**
     * 是否启用自我保护机制
     */
    boolean isSelfPreservationModeEnabled();
}

Map<String, RemoteRegionRegistry> regionNameVSRemoteRegistry 是 AbstractInstanceRegistry 抽象类的成员变量,key 是 remoteRegionUrlsWithName 配置中的 regionName,value 则是 initRemoteRegionRegistry() 方法中创建的RemoteRegionRegistry 对象。

// 配置remoteRegionUrlsWithName 
regionName1;regionUrl1,regionName2;regionUrl2...

RemoteRegionRegistry 类表示其他区域的注册表信息,配置 remoteRegion.registryFetchIntervalInSeconds 指定从其他区域拉取注册表信息的间隔时间,默认 30s

拉取成功后,将 readyForServingData 设置为 true,表示该区域的注册表已经可以提供服务。

Runnable remoteRegionFetchTask = new Runnable() {
    @Override
    public void run() {
        try {
            if (fetchRegistry()) {
                readyForServingData = true;
            } else {
                logger.warn("Failed to fetch remote registry. " +
                    "This means this eureka server " + 
                    "is not ready for serving traffic.");
            }
        }
    }
};

scheduler.schedule(
    new TimedSupervisorTask(
        "RemoteRegionFetch_" + regionName,
        scheduler,
        remoteRegionFetchExecutor,
        // 配置remoteRegion.registryFetchIntervalInSeconds
        serverConfig.getRemoteRegionRegistryFetchInterval(),
        TimeUnit.SECONDS,
        5,  // exponential backoff bound
        remoteRegionFetchTask
    ),
    serverConfig.getRemoteRegionRegistryFetchInterval(),
    TimeUnit.SECONDS);

remoteRegion.global.appWhiteListremoteRegion.{regionName}.appWhiteList 配置全局和 regionName 指定区域的拉取白名单,appName 不在白名单中的应用信息是无法拉取的。


PeerAwareInstanceRegistry 接口继承 InstanceRegistry 接口,提供以下功能:

public interface PeerAwareInstanceRegistry extends InstanceRegistry {
    /**
     * 初始化PeerAwareInstanceRegistryImpl,包括:
     *     1.实例化注册表缓存ResponseCacheImpl
     *     2.创建定时任务,定时更新numberOfRenewsPerMinThreshold
     *         配置renewalThresholdUpdateIntervalMs
     *         指定更新numberOfRenewsPerMinThreshold的时间间隔,默认15min
     *     3.初始化其他区域注册表regionNameVSRemoteRegistry
     */
    void init(PeerEurekaNodes peerEurekaNodes) throws Exception;
    /**
     * 是否可以对外提供注册表服务
     *     1.如果在调用openForTraffic方法时
     *       从其他Eureka节点拉取注册表失败则返回false
     *     2.如果remoteRegionRequired为true
     *       还需要等待其他区域注册表全部拉取成功后才返回true
     */
    boolean shouldAllowAccess(boolean remoteRegionRequired);
    /**
     * 从其他Eureka节点拉取注册表信息
     */
    int syncUp();
    /**
     * 注册实例信息
     */
    void register(InstanceInfo info, boolean isReplication);

    void statusUpdate(final String asgName,
                      final ASGResource.ASGStatus newStatus,
                      final boolean isReplication);
}

:在 LeaseManager 接口中已经声明了 register(T r, int leaseDuration, boolean isReplication) 方法的前提下,为什么在 PeerAwareInstanceRegistry 接口中再次声明 register(InstanceInfo info, boolean isReplication) 方法呢?原来 register(InstanceInfo info, boolean isReplication) 方法是在 syncUp() 方法中被调用,是将从其他 Eureka 节点拉取过来的注册表中的实例信息注册到本地注册表中

// com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl
public int syncUp() {
    // 统计从其他Eureka节点同步过来的实例信息数量
    int count = 0;
    // ...
    // 从其他Eureka节点拉取注册表信息
    Applications apps = eurekaClient.getApplications();
    for (Application app : apps.getRegisteredApplications()) {
        for (InstanceInfo instance : app.getInstances()) {
            // ...
            // 判断该实例的availabilityZone是否和当前Eureka节点属于同一个region
            // 如果是,则将该实例注册到本地注册表
            if (isRegisterable(instance)) {
                register(instance,
                         instance.getLeaseInfo().getDurationInSecs(),
                         true);
                count++;
            }
        } 
    }
    // ...
    return count;
}

PeerAwareInstanceRegistryImpl 类构造方法和 init 方法代码如下:

@Singleton
public class PeerAwareInstanceRegistryImpl
                extends AbstractInstanceRegistry
                implements PeerAwareInstanceRegistry {
    // startupTime、peerInstancesTransferEmptyOnStartup
    // 在openForTraffic方法被调用时赋值
    private long startupTime = 0;
    private boolean peerInstancesTransferEmptyOnStartup = true;

    // peerEurekaNodes在init方法被调用时赋值
    protected volatile PeerEurekaNodes peerEurekaNodes;
    // eurekaClient在构造方法被调用时赋值
    protected final EurekaClient eurekaClient;
    // instanceStatusOverrideRule在构造方法被调用时赋值
    private final InstanceStatusOverrideRule instanceStatusOverrideRule;
    // 定时调用updateRenewalThreshold方法
    private Timer timer = new Timer(
        "ReplicaAwareInstanceRegistry - RenewalThresholdUpdater", true);

    @Inject
    public PeerAwareInstanceRegistryImpl(
                EurekaServerConfig serverConfig,
                EurekaClientConfig clientConfig,
                ServerCodecs serverCodecs,
                EurekaClient eurekaClient) {
        super(serverConfig, clientConfig, serverCodecs);
        this.eurekaClient = eurekaClient;
        this.numberOfReplicationsLastMin = new MeasuredRate(1000 * 60 * 1);
        // We first check if the instance is STARTING or DOWN,
        // then we check explicit overrides,
        // then we check the status of a potentially existing lease.
        this.instanceStatusOverrideRule =
                new FirstMatchWinsCompositeRule(
                        new DownOrStartingRule(),
                        new OverrideExistsRule(overriddenInstanceStatusMap),
                        new LeaseExistsRule());
    }

    @Override
    public void init(PeerEurekaNodes peerEurekaNodes) throws Exception {
        // 1.统计每分钟和其他Eureka节点的同步频率
        this.numberOfReplicationsLastMin.start();
        // 2.赋值peerEurekaNodes属性,保存Eureka集群节点信息
        this.peerEurekaNodes = peerEurekaNodes;
        // 3.创建本地注册表缓存ResponseCacheImpl
        initializedResponseCache();
        // 4.创建TimerTask,通过Timer调度updateRenewalThreshold方法
        // 定时更新numberOfRenewsPerMinThreshold
        scheduleRenewalThresholdUpdateTask();
        // 5.创建其他区域的注册表RemoteRegionRegistry
        initRemoteRegionRegistry();
        // ...
    }
}
  1. 实现了 PeerAwareInstanceRegistry 接口,通过 eurekaClient 属性获得了从其他 Eureka 节点拉取注册表(PeerAwareInstanceRegistry#syncUp()方法)的能力,

  2. 通过 peerEurekaNodes 属性获得了将本地注册表的更新同步给其他 Eureka 节点(PeerAwareInstanceRegistryImpl#replicateToPeers()方法)的能力

:为什么不将 Eureka 节点之间同步更新数据的操作和拉取注册表的操作一起声明在 PeerAwareInstanceRegistry 接口中,而是另外通过 PeerEurekaNode 类去实现呢?

既然 numberOfRenewsPerMinThreshold 是通过实例数量实时计算为什么不将 numberOfRenewsPerMinThreshold 属性声明在 PeerAwareInstanceRegistryImpl 类中,而是声明在父类 AbstractInstanceRegistry 中?

instanceStatusOverrideRule 根据规则计算实例的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/823532.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

8.1day02苍穹外卖开发

今天完善的功能是新增员工的功能&#xff1b; 新增员工需要添加的数据和员工表中的字段存在差异&#xff0c;用DTO封装传入进来的数据&#xff0c;将DTO实体的数据拷贝给employ类中去&#xff0c;采用的方式是用 BeanUtils.copyProperties(employeeDTO,employee); //前面是数据…

lodop学习

lodop 前提&#xff1a;为满足js调用打印机功能&#xff0c;浏览器自带的打印会弹出一个预览框&#xff0c;实际在应用场景上不需要这个预览弹窗&#xff0c;点击页面打印要直接根据预设好的参数直接打印&#xff0c;这个时候看到了lodop这个插件。 步骤1&#xff1a;官网下载…

一文搞懂Redis架构演化之路

目录 从最简单的开始&#xff1a;单机版 Redis 数据持久化&#xff1a;有备无患 主从复制&#xff1a;多副本 哨兵&#xff1a;故障自动切换 分片集群&#xff1a;横向扩展 总结 这篇文章我想和你聊一聊 Redis 的架构演化之路。 现如今 Redis 变得越来越流行&#xff0c;…

C++ ——stack、queue容器模拟实现及deque容器底层介绍

deque文档 stack文档 deque文档 文章目录 &#x1f345;1. deque容器&#x1f352;deque底层&#x1f352;deque的优势&#x1f352;deque的劣势 &#x1fad0;2. stack模拟实现&#x1f95d;3. queue模拟实现 &#x1f345;1. deque容器 查看文档可发现&#xff0c;栈和队列都…

前中后序迭代统一格式遍历法(最好理解)js版本

说实话,有关二叉树遍历这块,特别是迭代版本,网上好多写的糊里糊涂的,尤其是将三种遍历统一风格的,基本都是看到一头雾水,我想了个比较直观点(自认为) 首先,以下图二叉树为例, 使用迭代法,无论哪种遍历顺序都要首先要开一个栈,同时还需要一个指针cur用于控制当前 接…

Java三大特征之继承【超详细】

文章目录 一、继承概念二、继承的语法三、父类成员访问3.1子类中访问父类的成员变量3.2子类和父类成员变量同名3.3子类中访问父类的成员方法 四、super关键字五、子类构造方法六、super和this七、再谈初始化八、protected 关键字九、继承方式十、final 关键字十一、继承与组合 …

RK DWC3 gadget模块 分析

1. dw3 core代码分析 文件&#xff1a;[drivers/usb/dwc3/core.c] dwc3_probe 函数主要申请dwc3_vendor 参数内存&#xff08;dwc3_vendor的dwc成员即是 struct dwc3结构体参数&#xff09;&#xff0c;对dwc3 通过设备树 以及寄存器信息对 dwc3的成员进行初始化&#xff0c;…

cloudstack平台host加入后,显示CPU speed为0GHz

一、环境说明 操作系统&#xff1a;openEuler 22.03CPU&#xff1a;Kunpeng-920&#xff0c;arm v8cloudstack&#xff1a;4.18libvirtd&#xff1a;6.2.0 二、问题描述 cloudstack平台初始化完成后&#xff0c;第一次加入host&#xff0c;系统虚拟机一直无法正常创建&#…

瑞吉外卖项目----(2)缓存优化

1 缓存优化 1.0 问题说明 1.1 环境搭建 将项目推送到远程仓库里&#xff0c;教程在git 提交远程仓库前建议取消代码检查 创建新的分支v1.0&#xff08;用于实现缓存优化&#xff09;并推送到远程仓库 1.1.1 maven坐标 导入spring-data-redis的maven坐标&#xff1a; &l…

PyTorch代码实战入门

人这辈子千万不要马虎两件事 一是找对爱人、二是选对事业 因为太阳升起时要投身事业 太阳落山时要与爱人相拥 一、准备数据集 蚂蚁蜜蜂数据集 蚂蚁蜜蜂的图片&#xff0c;文件名就是数据的label 二、使用Dataset加载数据 打开pycharm&#xff0c;选择Anaconda创建的pytorch环…

FTP Server

简介 FTP&#xff1a;File Transfer Protocol 文件传输协议&#xff1b;它工作在 OSI 模型的第七层&#xff0c; TCP 模型的第四层&#xff0c; 即应用层&#xff0c; 使用 TCP 传输而不是 UDP&#xff0c; 客户在和服务器建立连接前要经过一个“三次握手”的过程&#xff0c;…

捷码低代码|FreeContainer 自由布局组件详解

背景知识&#xff1a; 1、布局组件&#xff1a; 布局组件是一种用于在用户界面中安排和组织其他组件的组件。它们提供了一种简单的方法来控制和管理页面上组件的位置、大小和层次结构。布局组件可以是容器&#xff0c;可以包含其他组件&#xff0c;并确定它们在界面上的显示方式…

【MyBatis】 框架原理

目录 10.3【MyBatis】 框架原理 10.3.1 【MyBatis】 整体架构 10.3.2 【MyBatis】 运行原理 10.4 【MyBatis】 核心组件的生命周期 10.4.1 SqlSessionFactoryBuilder 10.4.2 SqlSessionFactory 10.4.3 SqlSession 10.4.4 Mapper Instances 与 Hibernate 框架相比&#…

深入理解MVVM架构模式

MVVM原理 MVVM是一种用于构建用户界面的软件架构模式&#xff0c;它的名称代表着三个组成部分&#xff1a;Model&#xff08;模型&#xff09;、View&#xff08;视图&#xff09;和ViewModel&#xff08;视图模型&#xff09;。MVVM的主要目标是将应用程序的UI与其底层数据模…

SERDES关键技术

目录 一、SERDES介绍 二、SERDES关键技术 2.1 多重相位技术 2.2 线路编解码技术 2.2.1 8B/10B编解码 2.2.2 控制字符&#xff08;Control Characters&#xff09; 2.2.3 Comma检测 2.2.4 扰码&#xff08;Scrambling&#xff09; 2.2.5 4B/5B与64B/66B编解码技术 2.3 包传…

Halcon学习之一维测量实战之测量矩形(一)

一、采集图像 (1)测量充电器 测量充电器的引脚,然后每次旋转充电器,让测量矩形都跟着它转,这就是定位+测量, (2)测量钥匙 (3)测量瓶盖 我们后面还会涉及到拟合的问

牛客网Verilog刷题——VL53

牛客网Verilog刷题——VL53 题目答案 题目 设计一个单端口RAM&#xff0c;它有&#xff1a; 写接口&#xff0c;读接口&#xff0c;地址接口&#xff0c;时钟接口和复位&#xff1b;存储宽度是4位&#xff0c;深度128。注意rst为低电平复位。模块的接口示意图如下。 输入输出描…

HDFS的QJM方案

Quorum Journal Manager仲裁日志管理器 介绍主备切换&#xff0c;脑裂问题解决---ZKFailoverController&#xff08;zkfc&#xff09;主备切换&#xff0c;脑裂问题解决-- Fencing&#xff08;隔离&#xff09;机制主备数据状态同步问题解决 HA集群搭建集群基础环境准备HA集群规…

解决git仓库无效问题

解决fatal: … not valid: is this a git repository?问题 凭证编辑修改成自己的账号密码即可解决

2023年第四届“华数杯”数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集身份认证…