8、Nacos服务注册服务端源码分析(七)

news2024/11/26 0:38:28

本文收录于专栏 Nacos 中 。

文章目录

  • 前言
  • 确定前端路由
  • CatalogController.listDetail()
  • ServiceManager
  • 总结


前言

前文我们分析了Nacos中客户端注册时数据分发的设计链路,本文根据Nacos前端页面请求,看下前端页面中的服务列表的数据源于哪里。

确定前端路由

我们已经向Nacos中注册了一个服务,现在去前端确定查询的路由是什么
在这里插入图片描述
确定前端请求路由:/nacos/v1/ns/catalog/services
通过路由确定后端代码位置:

package com.alibaba.nacos.naming.controllers;
CatalogController.listDetail()

CatalogController.listDetail()

/**
 * List service detail information.
 *
 * @param withInstances     whether return instances
 * @param namespaceId       namespace id
 * @param pageNo            number of page
 * @param pageSize          size of each page
 * @param serviceName       service name
 * @param groupName         group name
 * @param containedInstance instance name pattern which will be contained in detail
 * @param hasIpCount        whether filter services with empty instance
 * @return list service detail
 */
@Secured(action = ActionTypes.READ)
@GetMapping("/services")
public Object listDetail(@RequestParam(required = false) boolean withInstances,
        @RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
        @RequestParam(required = false) int pageNo, @RequestParam(required = false) int pageSize,
        @RequestParam(name = "serviceNameParam", defaultValue = StringUtils.EMPTY) String serviceName,
        @RequestParam(name = "groupNameParam", defaultValue = StringUtils.EMPTY) String groupName,
        @RequestParam(name = "instance", defaultValue = StringUtils.EMPTY) String containedInstance,
        @RequestParam(required = false) boolean hasIpCount) throws NacosException {
    //前端withInstances传的是false,不走这个分支
    if (withInstances) {
        return judgeCatalogService().pageListServiceDetail(namespaceId, groupName, serviceName, pageNo, pageSize);
    }
    //确定是走的这里获取的服务列表
    return judgeCatalogService()
            .pageListService(namespaceId, groupName, serviceName, pageNo, pageSize, containedInstance, hasIpCount);
}

查看judgeCatalogService().pageListService(namespaceId, groupName, serviceName, pageNo, pageSize, containedInstance, hasIpCount);的实现:

@Override
public Object pageListService(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize,
        String instancePattern, boolean ignoreEmptyService) throws NacosException {
    ObjectNode result = JacksonUtils.createEmptyJsonNode();
    List<ServiceView> serviceViews = new LinkedList<>();
    //获取服务列表
    Collection<Service> services = patternServices(namespaceId, groupName, serviceName);
    if (ignoreEmptyService) {
        services = services.stream().filter(each -> 0 != serviceStorage.getData(each).ipCount())
                .collect(Collectors.toList());
    }
    result.put(FieldsConstants.COUNT, services.size());
    services = doPage(services, pageNo - 1, pageSize);
    for (Service each : services) {
        ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(each).orElseGet(ServiceMetadata::new);
        ServiceView serviceView = new ServiceView();
        serviceView.setName(each.getName());
        serviceView.setGroupName(each.getGroup());
        serviceView.setClusterCount(serviceStorage.getClusters(each).size());
        serviceView.setIpCount(serviceStorage.getData(each).ipCount());
        serviceView.setHealthyInstanceCount(countHealthyInstance(serviceStorage.getData(each)));
        serviceView.setTriggerFlag(isProtectThreshold(serviceView, serviceMetadata) ? "true" : "false");
        serviceViews.add(serviceView);
    }
    result.set(FieldsConstants.SERVICE_LIST, JacksonUtils.transferToJsonNode(serviceViews));
    return result;
}

private Collection<Service> patternServices(String namespaceId, String group, String serviceName) {
    boolean noFilter = StringUtils.isBlank(serviceName) && StringUtils.isBlank(group);
    if (noFilter) {
    	//我们前端默认传的这两个参数都是空,所以会走这里的逻辑
        return ServiceManager.getInstance().getSingletons(namespaceId);
    }
    Collection<Service> result = new LinkedList<>();
    StringJoiner regex = new StringJoiner(Constants.SERVICE_INFO_SPLITER);
    regex.add(getRegexString(group));
    regex.add(getRegexString(serviceName));
    String regexString = regex.toString();
    for (Service each : ServiceManager.getInstance().getSingletons(namespaceId)) {
        if (each.getGroupedServiceName().matches(regexString)) {
            result.add(each);
        }
    }
    return result;
}

ServiceManager.getInstance()这里一看就是一个经典的单例写法,那我们接下来把精力放到getSingletons这个方法上。
namespaceId默认是public

ServiceManager

public Set<Service> getSingletons(String namespace) {
    return namespaceSingletonMaps.getOrDefault(namespace, new HashSet<>(1));
}

通过代码我们发现,获取制定namespace下的服务是从一个map中获取的。

/**
 * Nacos service manager for v2.
 *
 * @author xiweng.yy
 */
public class ServiceManager {
    
    private static final ServiceManager INSTANCE = new ServiceManager();
    
    private final ConcurrentHashMap<Service, Service> singletonRepository;
    
    private final ConcurrentHashMap<String, Set<Service>> namespaceSingletonMaps;
	
	//...
}

我们可以发现ServiceManager这个类是一个单例模式的实现,其中维护了两个map,其中一个namespaceSingletonMaps用于存放制定namespace下的服务,那么这个map中的数据是在什么时机存放进去的呢?

/**
 1. Get singleton service. Put to manager if no singleton.
 2.  3. @param service new service
 4. @return if service is exist, return exist service, otherwise return new service
 */
public Service getSingleton(Service service) {
    singletonRepository.computeIfAbsent(service, key -> {
        NotifyCenter.publishEvent(new MetadataEvent.ServiceMetadataEvent(service, false));
        return service;
    });
    Service result = singletonRepository.get(service);
    namespaceSingletonMaps.computeIfAbsent(result.getNamespace(), namespace -> new ConcurrentHashSet<>());
    namespaceSingletonMaps.get(result.getNamespace()).add(result);
    return result;
}

观察代码我们发现,往map中写数据的只有这一个方法,那么这个方法是在什么时机被调用的呢?
我们重新梳理之前客户端注册的部分逻辑:

  1. InstanceRequestHandler接收所有实例注册、注销相关的请求
  2. InstanceRequestHandler处理注册请求时,会调用EphemeralClientOperationServiceImpl中的registerInstance方法
  3. registerInstance方法中除了我们之前讲的发布客户端服务注册事件ClientOperationEvent.ClientRegisterServiceEvent之外,还会往ServiceManager中的map添加数据

registerInstance方法对ServiceManager的处理逻辑如下:

Service singleton = ServiceManager.getInstance().getSingleton(service);

总结

通过以上梳理,我们知道了前端服务列表中获取的数据是源于ServiceManager类中一个map的缓存,缓存中的数据是在客户端服务注册时添加进去的。

先梳理脉络,然后以点到面,一切都会逐渐清晰。

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

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

相关文章

Complete Probability Spaces

See https://math.stackexchange.com/questions/4095399/complete-probability-spaces

山西电力市场日前价格预测【2023-10-03】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-10-03&#xff09;山西电力市场全天平均日前电价为278.17元/MWh。其中&#xff0c;最高日前电价为477.85元/MWh&#xff0c;预计出现在18: 45。最低日前电价为0.00元/MWh&#xff0c;预计出…

概率论中的filtration中文叫什么?

1、2 - Financial Markets with Continuous Time- https://doi.org/10.1016/B978-1-78548-046-1.50002-8 2、Filtration (probability theory)-https://handwiki.org/wiki/Filtration_(probability_theory)#:~:textA%20filtration%20F%20%3D%20%28F%20i%29%20i%20%E2%88%88,…

lv6 嵌入式开发-Flappy bird项目(信号机制、定时器功能实现)

目录 1 信号(signal) 2 设置信号响应方式 – signal 3 设置定时器 4 示例 问题&#xff1a; getch()阻塞获取键盘按键输入&#xff0c; 怎么操作才能不影响小鸟下落和管道移动&#xff1f; getch如果阻塞&#xff0c;下面的程序都是无法执行。通过信号机制方式实现。 1 …

分享46个Python源代码总有一个是你想要的

分享46个Python源代码总有一个是你想要的 下载链接&#xff1a;https://pan.baidu.com/s/1oZPrXHwgzcvVpB36_dA72A?pwd8888 提取码&#xff1a;8888 chat-web项目的python后端 Django WEB商城网站项目 django-实时接口获取中国各个城市、省份、国家的新型冠状肺炎 NewsSp…

多线程 - 阻塞式队列

阻塞队列 阻塞队列,也是一个队列 ~~ 先进先出 实际上有一些特殊的队列,不一定非得遵守先进先出的 ~~ 优先级队列(PriorityQueue) 阻塞队列,也是特殊的队列,虽然也是先进先出的,但是带有特殊的功能: 阻塞 如果队列为空,执行出队列操作,就会阻塞.阻塞到另一个线程往队列里添加元…

Go:实现SMTP邮件发送订阅功能(包含163邮箱、163企业邮箱、谷歌gmail邮箱)

需求很简单&#xff0c;就是用户输入自己的邮箱后&#xff0c;使用官方邮箱给用户发送替邮件模版 目录 前置邮件模版邮箱开启SMTP服务163邮箱163企业邮箱谷歌gmail邮箱腾讯企业邮箱-失败其他邮箱-未操作 邮件发送核心代码config.yaml配置读取邮件相关配置发送邮件 附录 前置 邮…

深度学习笔记之线性代数

深度学习笔记之线性代数 一、向量 在数学表示法中&#xff0c;向量通常记为粗体小写的符号&#xff08;例如&#xff0c;x&#xff0c;y&#xff0c;z&#xff09;当向量表示数据集中的样本时&#xff0c;它们的值具有一定的现实意义。例如研究医院患者可能面临的心脏病发作风…

Ubuntu系统初始设置

更换国内源 安装截图工具 安装中文输入法 安装QQ 参考&#xff1a; 安装双系统win10Ubuntu20.04LTS&#xff08;详细到我自己都害怕&#xff09; 引导方式磁盘分区方法UEFIGPTLegancyMBR 安装网络助手 sudo apt install net-tools 安装VS Code 使用从官网下载.deb安装包…

MySQL使用Xtrabackup在线做主从

1、主库上操作 1.1前提 172.16.11.2&#xff08;主库&#xff09; 172.16.11.4&#xff08;从库&#xff09; 在执行备份之前&#xff0c;确保数据库没有锁定&#xff0c;以避免备份期间的任何写操作。 确保主库上的 MySQL 服务器正在运行&#xff0c;以便备份数据的一致性。…

八、2023.10.2.Linux(二).8

文章目录 17、简述一下虚拟内存和物理内存&#xff0c;为什么要用虚拟内存&#xff0c;好处是什么&#xff1f;18、虚拟地址到物理地址怎么映射的&#xff1f;19、说说堆栈溢出是什么&#xff0c;会怎么样&#xff1f;20、简述操作系统中malloc的实现原理?21、说说进程空间从高…

uboot启动流程-涉及board_init_f 函数

一. uboot启动流程 _main 函数中会调用 board_init_f 函数&#xff0c;本文简单分析一下 board_init_f 函数。 二. board_init_f 函数 board_init_f 函数主要有两个工作&#xff1a; (1) 初始化一系列外设&#xff0c;比如串口、定时器&#xff0c;或者打印一些消息等。…

Docker Tutorial

什么是Docker 为每个应用提供完全隔离的运行环境 Dockerfile&#xff0c; Image&#xff0c;Container Image&#xff1a; 相当于虚拟机的快照&#xff08;snapshot&#xff09;里面包含了我们需要部署的应用程序以及替它所关联的所有库。通过image&#xff0c;我们可以创建很…

音乐创作软件:ToneLIB Jam v4.7.8 Crack

从强大的选项卡编辑器到 3D 模式 Tonelib Jam 是一款用于播放和创作音乐的综合软件应用程序。TL Jam专为初学者和经验丰富的吉他手而设计&#xff0c;可以提供一个完美的平台来掌握乐器&#xff0c;让您轻松学习自己喜欢的歌曲或设置高效的日常吉他练习程序。TL Jam 具有功能强…

目标检测|边框检测框转换,交并比计算 代码实现

文章目录 1. 相互转换的函数2.交并比实现 在目标检测任务中&#xff0c;非常重要的一部分就是框出检测框 这就需要检测框的位置大小等一些信息 一般我们有如下两种方式标记一个检测的位置和大小 1 两点法 检测框左上角坐标(x1,y1)&#xff0c;检测框右下角坐标&#xff08;x2…

2023年最新云存储工具排行榜:找到适合你的云存储服务

随着数据规模的不断增长&#xff0c;传统的本地存储已经无法满足用户的需求。云存储工具通过提供灵活、安全和高效的数据存储服务&#xff0c;成为了现代化的数据管理方式。在众多云存储工具中&#xff0c;有一些在功能和性能方面表现出色&#xff0c;成为用户首选。下面是2023…

时间序列-AR模型与MA模型的原理与实现

文章目录 1 自回归模型AR Model1.1 自回归模型 vs 多元线性回归模型1.1.1 线性回归1.1.2 AR(1)模型1.1.3 AR(p)模型 1.2 AR建模问题 2 移动平均模型 MA Model2.1 MA模型的数学表示2.1.1 MA(1)模型2.2.2 MA(q)模型 2.2 MA建模问题 ARIMA模型是AR模型&#xff08;自回归模型&…

计算机网络(二):物理层

参考引用 计算机网络微课堂-湖科大教书匠计算机网络&#xff08;第7版&#xff09;-谢希仁 1. 物理层的基本概念 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流物理层为数据链路层屏蔽了各种传输媒体的差异&#xff0c;使数据链路层只需要考虑如何完成本…

levelDB引擎

一、背景 1.1、影响磁盘性能的因素&#xff1a; 主要受限于磁盘的寻道时间&#xff0c;优化磁盘数据访问的方法是尽量减少磁盘的IO次数。磁盘数据访问效率取决于磁盘IO次数&#xff0c;而磁盘IO次数又取决于数据在磁盘上的组织方式。磁盘数据存储大多采用B树类型数据结构&…

排序篇(三)----交换排序

排序篇(三)----交换排序 1.冒泡排序 基本思想: ​ 通过不断地比较相邻的元素&#xff0c;将较大的元素往后移动&#xff0c;从而实现排序的目的。 具体的步骤如下&#xff1a; 从待排序的数组中选择相邻的两个元素进行比较&#xff0c;如果前一个元素大于后一个元素&#…