Nacos 客户端服务发现源码分析-篇六

news2024/12/23 18:10:04

Nacos 客户端服务发现源码分析-篇六

🕐Nacos 客户端服务注册源码分析-篇一

🕑Nacos 客户端服务注册源码分析-篇二

🕒Nacos 客户端服务注册源码分析-篇三

🕓Nacos 服务端服务注册源码分析-篇四

🕔Nacos 服务端健康检查-篇五


注册发现流程

前面的几篇探究了客户端服务注册,服务端发现,以及服务端的健康检测方面的源码。

如果通过一个图去连接他们之间的关系其实,Nacos 客户端的服务发现,其实就是客户端实体参数封装,调用服务端接口请求,获得返回实例结果列表的过程。

image-20230418211222559

对于 NacosService 获取服务列表,在获取服务列表的过程中还涉及到通讯流程协议(Http / gPRC),订阅流程、故障转移等。

那么对于这些到底是怎么实现的呢?我们接着往下一点点的剖析关于 NamingTest 测试类中提供的源码流程。

@Test
public void testServiceList() throws Exception {
    ......
    NamingService namingService = NacosFactory.createNamingService(properties);
namingService.registerInstance("nacos.test.1", instance);
	ThreadUtils.sleep(5000L);
	List<Instance> list = namingService.getAllInstances("nacos.test.1");
    ......
}

前面的关于 registerInstance 方法我们前几篇已经分析完,我们接下来关注 getAllInstance 方法内部是怎么实现的,这里返回的 List 其实就是客户端在注册完毕后返回的实例列表。

我们先打断点看一下,官方提供的 MamingTest 中返回的 list 中都有些什么信息。

image-20230418212323531

而这些数据就是在客户端返回的数据信息,运行之前的 9002 项目我们看观察一下。

image-20230418212719865

我们进入 getAllInstances 方法一探究竟。。。

@Override
public List<Instance> getAllInstances(String serviceName) throws NacosException {
    return getAllInstances(serviceName, new ArrayList<String>());
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException {
    return getAllInstances(serviceName, clusters, true);
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters, boolean subscribe)
        throws NacosException {
    return getAllInstances(serviceName, Constants.DEFAULT_GROUP, clusters, subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters,
        boolean subscribe) throws NacosException {
    ServiceInfo serviceInfo;
    String clusterString = StringUtils.join(clusters, ",");
    if (subscribe) {
        serviceInfo = serviceInfoHolder.getServiceInfo(serviceName, groupName, clusterString);
        if (null == serviceInfo) {
            serviceInfo = clientProxy.subscribe(serviceName, groupName, clusterString);
        }
    } else {
        serviceInfo = clientProxy.queryInstancesOfService(serviceName, groupName, clusterString, 0, false);
    }
    List<Instance> list;
    if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
        return new ArrayList<Instance>();
    }
    return list;
}

可以看到在 NacosNamingService 服务当中有大量的 getAllInstances 的重载,提供一些默认的参数。

打个断点玩玩看,内部这些参数都是怎么进行调用,并且完成处理的。

image-20230418214156751

@Override
public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters,
        boolean subscribe) throws NacosException {
    ServiceInfo serviceInfo;
    //获取当前的集群
    String clusterString = StringUtils.join(clusters, ",");
    //是否订阅模式(默认 true )
    if (subscribe) {
        //获取客户端缓存中获取服务信息
        serviceInfo = serviceInfoHolder.getServiceInfo(serviceName, groupName, clusterString);
        if (null == serviceInfo) {
            //如果本地的缓存不存在服务信息,则进行订阅
            serviceInfo = clientProxy.subscribe(serviceName, groupName, clusterString);
        }
    } else {
        //如果未订阅服务信息,则直接从服务器进行查询
        serviceInfo = clientProxy.queryInstancesOfService(serviceName, groupName, clusterString, 0, false);
    }
    List<Instance> list;
    //从服务信息当中获取实例列表
    if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
        return new ArrayList<Instance>();
    }
    return list;
}
  • 分组名称默认:DEFAULT_GROUOP
  • 集群列表:默认为空数组
  • 是否订阅:订阅

可以看到上面的几个关键方法所执行的功能基本就这么几个。。。

可以通过一个流程图进行分析。

image-20230418215956134

那么对于 缓存获取与本地缓存内部是怎么实现,以及从服务器端进行查询服务是怎么实现的呢?我们进入具体的实现方法中瞅瞅。。。

客户端服务信息缓存的实现

进入 serviceInfoHolder.getServiceInfo() 方法当中看具体的实现

public ServiceInfo getServiceInfo(final String serviceName, final String groupName, final String clusters) {
    NAMING_LOGGER.debug("failover-mode: " + failoverReactor.isFailoverSwitch());
    String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
    String key = ServiceInfo.getKey(groupedServiceName, clusters);
    //当前的客户端连接是否故障,如果故障 isFailoverSwitch 返回的结果是 false
    if (failoverReactor.isFailoverSwitch()) {
        return failoverReactor.getService(key);
    }
    //返回当前本地缓存中的数据
    return serviceInfoMap.get(key);
}

serviceInfoMap 的实现

//线程安全的
private final ConcurrentMap<String, ServiceInfo> serviceInfoMap;
public ServiceInfoHolder(String namespace, Properties properties) {
    initCacheDir(namespace, properties);
    if (isLoadCacheAtStart(properties)) {
        //DiskCache.read() 从磁盘中读取缓存信息
        this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(DiskCache.read(this.cacheDir));
    } else {
        //如果是第一次未有缓存则初始化一个默认大小的集合
        this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(16);
    }
    this.failoverReactor = new FailoverReactor(this, cacheDir);
    this.pushEmptyProtection = isPushEmptyProtect(properties);
}
private void initCacheDir(String namespace, Properties properties) {
    String jmSnapshotPath = System.getProperty(JM_SNAPSHOT_PATH_PROPERTY);
    String namingCacheRegistryDir = "";
    if (properties.getProperty(PropertyKeyConst.NAMING_CACHE_REGISTRY_DIR) != null) {
        namingCacheRegistryDir = File.separator + properties.getProperty(PropertyKeyConst.NAMING_CACHE_REGISTRY_DIR);
    }
    
    if (!StringUtils.isBlank(jmSnapshotPath)) {
        //初始化获取磁盘中缓存信息的 key
        cacheDir = jmSnapshotPath + File.separator + FILE_PATH_NACOS + namingCacheRegistryDir
                + File.separator + FILE_PATH_NAMING + File.separator + namespace;
    } else {
        cacheDir = System.getProperty(USER_HOME_PROPERTY) + File.separator + FILE_PATH_NACOS + namingCacheRegistryDir
                + File.separator + FILE_PATH_NAMING + File.separator + namespace;
    }

通过上面的实现可以发现哈,其实在 Nacos 的内部是通过一个线程安全的 ConcurrentHashMap 进行缓存信息的维护的,其缓冲的具体 key 分两种情况一种是没有其缓存快照的一种是存在缓存快照的。

initCacheDir() 初始化缓存信息

image-20230418231102010

image-20230418231115233

订阅模式的实现

image-20230419102911056

@Override
public ServiceInfo subscribe(String serviceName, String groupName, String clusters) throws NacosException {
    String serviceNameWithGroup = NamingUtils.getGroupedName(serviceName, groupName);
    String serviceKey = ServiceInfo.getKey(serviceNameWithGroup, clusters);
    //开启定时调度 UpdateTask
    serviceInfoUpdateService.scheduleUpdateIfAbsent(serviceName, groupName, clusters);
    //获取缓存中的 ServiceInfo
    ServiceInfo result = serviceInfoHolder.getServiceInfoMap().get(serviceKey);
    if (null == result) {
        //如果缓存中没有数据,则进行订阅逻辑处理,基于 gRPC 协议
        result = grpcClientProxy.subscribe(serviceName, groupName, clusters);
    }
    //serviceInfo 本地缓存处理
    serviceInfoHolder.processServiceInfo(result);
    return result;
}
  1. 订阅方法先开启定时任务,这个定时任务的主要作用就是用来定时同步服务的实例信息操作,但是如果是首次这里将会直接返回下一步进行
  2. 判断本地的缓存中是否有 serviceInfo 信息存在,如果存在直接返回。如果不存在,则会默认的采用 gRPC 协议进行订阅服务,并且返回 serviceInfo
  3. grpcClientProxy 的 subscribe 订阅方法向服务器端发送一个订阅的请求,并将订阅的信息返回
  4. 最终是将 serviceInfo 本地缓存进行处理。在 processServiceInfo 方法中,将获取最新的 ServiceInfo 与本地内存中的 ServiceInfo 进行比较,完成更新,发布时间的变更,磁盘文件存储等操作。对于这一步的操作,其实在 订阅定时任务 中也进行了同样的处理。

以上就是关于客户端服务发现的大致流程。。。。

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

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

相关文章

ChatGPT神器免费使用,告别昂贵低效工具

大家好&#xff0c;今天我要向大家介绍一款免费的ChatGPT使用网址&#xff0c;它可以让你轻松地使用ChatGPT进行AI创作&#xff01;而且&#xff0c;这个网址还是免费的&#xff0c;不需要担心会有额外的费用。 ChatGPT是一种非常强大的AI技术&#xff0c;可以用于各种领域&…

《PyTorch 深度学习实践》第11讲 卷积神经网络(高级篇)

文章目录 1 Inception Module1.1 11卷积1.2 Inception模块结构1.3 完整代码 2 残差网络(Residual Network) 该专栏内容为对该视频的学习记录&#xff1a;【《PyTorch深度学习实践》完结合集】 专栏的全部代码、数据集和课件全放在个人GitHub了&#xff0c;欢迎自取。 1 Incept…

数据库实验 | 第3关:建立和调用存储函数

任务描述 本关任务&#xff1a; 销售数据库有顾客、销售单数据表 顾客gk数据表有会员号hyh、姓名name、性别sex、电话tel、部门dept字段 销售单xsd数据表有销售单号xsdh、会员号hyh、雇员号gyh、销售日期xsrq、应付款yfk、实际付款sjfk字段 任务要求 建立存储过程 gkjb(nf …

Obsidian中如何创作思维导图Mind-map

使用插件 obsidian-mind-map 1.直接在社区下载安装 设置快捷键或者在左侧竖形打开命令面板搜索关键字“mind”&#xff0c; 或者为了便于使用&#xff0c;设置快捷键&#xff0c;在设置-第三方插件中-选择快捷键 然后按下你想设置的快捷键就可以 我这里设置成了CtrlAltM ,M是…

小程序的组件化开发

目录&#xff1a; 1 小程序组件化思想 2 自定义组件的过程 3 组件样式实现细节 4 组件使用过程通信 5 组件插槽定义使用 6 Component构造器 在小程序里面需要创建组件的话需要在最外层建component包&#xff0c;然后在使用新建component来创建类似page的4个文件&#xff…

知乎版ChatGPT「知海图AI」加入国产大模型乱斗,称效果与GPT-4持平

“2023知乎发现大会”上&#xff0c;知乎创始人、董事长兼CEO周源和知乎合作人、CTO李大海共同宣布了知乎与面壁智能联合发布“知海图AI”中文大模型。 周源据介绍&#xff0c;知乎与面壁智能达成深度合作&#xff0c;共同开发中文大模型产品并推进应用落地。目前&#xff0c;知…

AUTOSAR存储服务之FEE换页策略介绍

概述 如下图是AUTOSAR Memory Stack的架构图,对于Memory Stack的介绍请参考AUTOSAR MemoryStack详细介绍_钢琴上的汽车软件的博客-CSDN博客 随着现在MCU携带的内置flash空间越来越大,从成本节省以及方便使用等方面考虑,在产品设计和开发过程中常用Flash EEPROM Emulation技…

CTFHub | eval执行

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

手推广告论文(二)Wide Deep 推荐系统算法Wide Deep Learning for Recommender Systems

Wide & Deep Learning for Recommender Systems 论文地址https://arxiv.org/pdf/1606.07792.pdf 摘要 广义线性模型结合非线性特征转换&#xff0c;在处理具有大规模稀疏输入的回归和分类问题中已被广泛应用。通过一系列交叉积特征转换来记忆特征交互既有效又具有解释性…

【分布式事务 本地部署Seata服务】分布式事务框架Seata本地部署详细讲解

前言 这篇文章我会从0到1详细搭建分布式事务框架seata的使用&#xff0c;那么我们首先要先了解一下什么是分布式事务&#xff1f; 本篇文章是本地启动seata服务并且注册到nacos中&#xff0c;在SpringCloud中整合seata框架请转移下方连接 点我跳转SpringCloud整合seata教程&…

VMware ESXi 8.0U1 Unlocker OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版)

发布 ESXi 8.0U1 集成驱动版&#xff0c;在个人电脑上运行企业级工作负载 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-8-u1-sysin/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 2023-04-18, VMware vSp…

【真北直播笔记】董越:简明DevOps学习地图

缘起 真北敏捷社区的宗旨是&#xff1a;求知、连接。求知就是学习&#xff0c;家里没矿的话&#xff0c;学习是一个人最重要的动力之源。连接就是把人拉在一起&#xff0c;我们相信人与人的互动会带来美好的变化。今天的直播是把大家拉在一起学习&#xff0c;就是求知、连接。 …

【万人推荐】黑客成长技术清单

最近两天&#xff0c;在reddit安全板块和Twitter上有个GitHub项目很火&#xff0c;叫“Awesome Hacking”。 “Awesome Hacking”在reddit上有超过四百个赞&#xff0c;但管理员后来认为不适合该板块&#xff08;Awesome类项目没有新的内容&#xff09;&#xff0c;给了“rejec…

十大排序算法之插入排序、希尔排序、选择排序

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【数据结构初阶&#xff08;C实现&#xff09;】 本篇主要讲解八大排序算法中的三种排序&#xff0c;分别是&#xff1a;插入排序、希尔排…

家用洗地机有什么优缺点?实用的洗地机分享

随着科技的不断发展&#xff0c;家庭清洁设备也在不断更新换代。现在市场上最常见的家用清洁设备包括洗地机、扫地机器人和吸尘器。这些设备各有优缺点&#xff0c;但在清洁效果、清洁范围和清洁方式等方面存在差异。洗地机是一种专业的清洁设备&#xff0c;它能够深度清洁地面…

SpringCloud之Gateway组件简介

网关的理解 网关类似于海关或者大门&#xff0c;出入都需要经过这个网关。别人不经过这个网关&#xff0c;永远也看不到里面的东西。可以在网关进行条件过滤&#xff0c;比如大门只有对应的钥匙才能入内。网关和大门一样&#xff0c;永远暴露在最外面 不使用网关 前端需要记住每…

Javascript进阶专题总结(函数、异步编程、设计模式)

函数式编程什么时候用 编程方法&#xff1a;函数式(js)&#xff0c;面向对象(java,c)&#xff0c;命令式 函数式&#xff08;工具式操作&#xff09; 优点&#xff1a;JavaScript种函数是一等公民&#xff0c;便于拆分组合可扩展性好&#xff0c;方便tree-shaking 缺点&…

【Linux系统】系统安全及应用二

开关安全控制一、开个安全控制1.1调整BIOS引导设置1.2GRUB限制1.3终端安全控制二、系统弱口令检查2.1安装JR工具三、网络端口扫描3.1NMAP端口扫描3.2NETSTAT&#xff0c;SS查看端口信息一、开个安全控制 1.1调整BIOS引导设置 将第一引导设备设为当前系统所在硬盘禁止从其他设…

1-时间复杂度分析

时间复杂度 ①what&#xff1a; 指执行当前算法所消耗的时间 ②简介结论&#xff1a; 时间复杂度由多项式T(n)中最高阶的项来决定&#xff0c;系数的影响忽略即可 例子&#xff1a; 操作数量T(n) 时间复杂度O(f(n)) 常数&#xff0c;比如 100000&#xff08;即&#xff1…

ChatGPT将批量文档翻译成中文的方法

文档翻译成中文软件是指在处理文档时&#xff0c;自动将文档中的内容翻译成中文的软件。这些软件通常采用自然语言处理技术&#xff0c;通过对待翻译文本的分词、词义分析、语法分析等多种技术处理&#xff0c;实现对文本中的单词、短语、句子等级别的翻译。 文档翻译成中文软件…