Spring Cloud Nacos源码讲解(二)- Nacos客户端服务注册源码分析

news2024/10/7 20:31:25

Nacos客户端服务注册源码分析

服务注册信息

​ 我们从Nacos-Client开始说起,那么说到客户端就涉及到服务注册,我们先了解一下Nacos客户端都会将什么信息传递给服务器,我们直接从Nacos Client项目的NamingTest说起

public class NamingTest {
    
    @Test
    public void testServiceList() throws Exception {
        
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
        properties.put(PropertyKeyConst.USERNAME, "nacos");
        properties.put(PropertyKeyConst.PASSWORD, "nacos");
        
        Instance instance = new Instance();
        instance.setIp("1.1.1.1");
        instance.setPort(800);
        instance.setWeight(2);
        Map<String, String> map = new HashMap<String, String>();
        map.put("netType", "external");
        map.put("version", "2.0");
        instance.setMetadata(map);
    
        NamingService namingService = NacosFactory.createNamingService(properties);
        namingService.registerInstance("nacos.test.1", instance);
        
        ThreadUtils.sleep(5000L);
        
        List<Instance> list = namingService.getAllInstances("nacos.test.1");
        
        System.out.println(list);
        
        ThreadUtils.sleep(30000L);
        //        ExpressionSelector expressionSelector = new ExpressionSelector();
        //        expressionSelector.setExpression("INSTANCE.metadata.registerSource = 'dubbo'");
        //        ListView<String> serviceList = namingService.getServicesOfServer(1, 10, expressionSelector);
        
    }
}

​ 其实这就是客户端注册的一个测试类,它模仿了一个真实的服务注册进Nacos的过程,包括NacosServer连接、实例的创建、实例属性的赋值、注册实例,所以在这个其中包含了服务注册的核心代码,仅从此处的代码分析,可以看出,Nacos注册服务实例时,包含了两大类信息:Nacos Server连接信息和实例信息。

Nacos Server连接信息

Nacos Server连接信息,存储在Properties当中,包含以下信息:

  • Server地址:Nacos服务器地址,属性的key为serverAddr;
  • 用户名:连接Nacos服务的用户名,属性key为username,默认值为nacos;
  • 密码:连接Nacos服务的密码,属性key为password,默认值为nacos;

实例信息

注册实例信息用Instance对象承载,注册的实例信息又分两部分:实例基础信息和元数据。

实例基础信息包括

  • instanceId:实例的唯一ID;
  • ip:实例IP,提供给消费者进行通信的地址;
  • port: 端口,提供给消费者访问的端口;
  • weight:权重,当前实例的权限,浮点类型(默认1.0D);
  • healthy:健康状况,默认true;
  • enabled:实例是否准备好接收请求,默认true;
  • ephemeral:实例是否为瞬时的,默认为true;
  • clusterName:实例所属的集群名称;
  • serviceName:实例的服务信息;

Instance类包含了实例的基础信息之外,还包含了用于存储元数据的metadata(描述数据的数据),类型为HashMap,从当前这个Demo中我们可以得知存放了两个数据:

  • netType:顾名思义,网络类型,这里的值为external,也就是外网的意思;
  • version:版本,Nacos的版本,这里是2.0这个大版本。

除了Demo中这些“自定义”的信息,在Instance类中还定义了一些默认信息,这些信息通过get方法提供:

public long getInstanceHeartBeatInterval() {
    return getMetaDataByKeyWithDefault(PreservedMetadataKeys.HEART_BEAT_INTERVAL,
                                       Constants.DEFAULT_HEART_BEAT_INTERVAL);
}

public long getInstanceHeartBeatTimeOut() {
    return getMetaDataByKeyWithDefault(PreservedMetadataKeys.HEART_BEAT_TIMEOUT,
                                       Constants.DEFAULT_HEART_BEAT_TIMEOUT);
}

public long getIpDeleteTimeout() {
    return getMetaDataByKeyWithDefault(PreservedMetadataKeys.IP_DELETE_TIMEOUT,
                                       Constants.DEFAULT_IP_DELETE_TIMEOUT);
}

public String getInstanceIdGenerator() {
    return getMetaDataByKeyWithDefault(PreservedMetadataKeys.INSTANCE_ID_GENERATOR,
                                       Constants.DEFAULT_INSTANCE_ID_GENERATOR);
}

上面的get方法在需要元数据默认值时会被用到:

  • preserved.heart.beat.interval:心跳间隙的key,默认为5s,也就是默认5秒进行一次心跳;
  • preserved.heart.beat.timeout:心跳超时的key,默认为15s,也就是默认15秒收不到心跳,实例将会标记为不健康;
  • preserved.ip.delete.timeout:实例IP被删除的key,默认为30s,也就是30秒收不到心跳,实例将会被移除;
  • preserved.instance.id.generator:实例ID生成器key,默认为simple;

这些都是Nacos默认提供的值,也就是当前实例注册时会告诉Nacos Server说:我的心跳间隙、心跳超时等对应的值是多少,你按照这个值来判断我这个实例是否健康。

有了这些信息,我们基本是已经知道注册实例时需要传递什么参数,需要配置什么参数了。

NamingService接口

​ NamingService接口是Nacos命名服务对外提供的一个统一接口,看对应的源码就可以发现,它提供了大量实例相关的接口方法:

  • 服务实例注册

    void registerInstance(...) throws NacosException;
    
  • 服务实例注销

    void deregisterInstance(...) throws NacosException;
    
  • 获取服务实例列表

    List<Instance> getAllInstances(...) throws NacosException;
    
  • 查询健康服务实例

    List<Instance> selectInstances(...) throws NacosException;
    
  • 查询集群中健康的服务实例

    List<Instance> selectInstances(....List<String> clusters....)throws NacosException;
    
  • 使用负载均衡策略选择一个健康的服务实例

    Instance selectOneHealthyInstance(...) throws NacosException;
    
  • 订阅服务事件

    void subscribe(...) throws NacosException;
    
  • 取消订阅服务事件

    void unsubscribe(...) throws NacosException;
    
  • 获取所有(或指定)服务名称

    ListView<String> getServicesOfServer(...) throws NacosException;
    
  • 获取所有订阅的服务

     List<ServiceInfo> getSubscribeServices() throws NacosException;
    
  • 获取Nacos服务的状态

    String getServerStatus();
    
  • 主动关闭服务

    void shutDown() throws NacosException
    

在这些方法中提供了大量的重载方法,应用于不同场景和不同类型实例或服务的筛选,所以我们只需要在不同的情况下使用不同的方法即可。

NamingService的实例化是通过NamingFactory类和上面的Nacos服务信息,从代码中可以看出这里采用了反射机制来实例化NamingService,具体的实现类为NacosNamingService:

public static NamingService createNamingService(Properties properties) throws NacosException {
    try {
        Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");
        Constructor constructor = driverImplClass.getConstructor(Properties.class);
        return (NamingService) constructor.newInstance(properties);
    } catch (Throwable e) {
        throw new NacosException(NacosException.CLIENT_INVALID_PARAM, e);
    }
}

NacosNamingService的实现

​ 在示例代码中使用了NamingService的registerInstance方法来进行服务实例的注册,该方法接收两个参数,服务名称和实例对象。这个方法的最大作用是设置了当前实例的分组信息。我们知道,在Nacos中,通过Namespace、group、Service、Cluster等一层层的将实例进行环境的隔离。在这里设置了默认的分组为“DEFAULT_GROUP”。

@Override
public void registerInstance(String serviceName, Instance instance) throws NacosException {
    registerInstance(serviceName, Constants.DEFAULT_GROUP, instance);
}

紧接着调用的registerInstance方法如下,这个方法实现了两个功能:

​ 第一,检查心跳时间设置的对不对(心跳默认为5秒)

​ 第二,通过NamingClientProxy这个代理来执行服务注册操作

@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    NamingUtils.checkInstanceIsLegal(instance);//检查心跳
    clientProxy.registerService(serviceName, groupName, instance);//通过代理执行服务注册操作
}

通过clientProxy我们发现NamingClientProxy这个代理接口的具体实现是有NamingClientProxyDelegate来完成的,这个可以从NacosNamingService构造方法中来看出。

public NacosNamingService(Properties properties) throws NacosException {
    init(properties);
}

初始化在init方法中

private void init(Properties properties) throws NacosException {
    ValidatorUtils.checkInitParam(properties);
    this.namespace = InitUtils.initNamespaceForNaming(properties);
    InitUtils.initSerialization();
    InitUtils.initWebRootContext(properties);
    initLogName(properties);

    this.changeNotifier = new InstancesChangeNotifier();
    NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384);
    NotifyCenter.registerSubscriber(changeNotifier);
    this.serviceInfoHolder = new ServiceInfoHolder(namespace, properties);
    this.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, properties, changeNotifier);//在这里进行了初始化,并看出使用的是NamingClientProxyDelegate来完成的
}

NamingClientProxyDelegate中实现

根据上方的分析和源码的阅读,我们可以发现NamingClientProxy调用registerService实际上调用的就是NamingClientProxyDelegate的对应方法:

@Override
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
    getExecuteClientProxy(instance).registerService(serviceName, groupName, instance);
}

真正调用注册服务的并不是代理实现类,而是根据当前实例是否为瞬时对象,来选择对应的客户端代理来进行请求的:

如果当前实例为瞬时对象,则采用gRPC协议(NamingGrpcClientProxy)进行请求,否则采用http协议(NamingHttpClientProxy)进行请求。默认为瞬时对象,也就是说,2.0版本中默认采用了gRPC协议进行与Nacos服务进行交互。

private NamingClientProxy getExecuteClientProxy(Instance instance) {
    return instance.isEphemeral() ? grpcClientProxy : httpClientProxy;
}

NamingGrpcClientProxy中实现

关于gRPC协议(NamingGrpcClientProxy),我们后续在做展开,我们主要关注一下registerService方法实现,这里其实做了两件事情

  1. 缓存当前注册的实例信息用于恢复,缓存的数据结构为ConcurrentMap<String, Instance>,key为“serviceName@@groupName”,value就是前面封装的实例信息。
  2. 另外一件事就是封装了参数,基于gRPC进行服务的调用和结果的处理。
@Override
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
    NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance {}", namespaceId, serviceName,
                       instance);
    redoService.cacheInstanceForRedo(serviceName, groupName, instance);//缓存数据
    doRegisterService(serviceName, groupName, instance);//基于gRPC进行服务的调用
}

总结流程

汇总流程图:

在这里插入图片描述

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

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

相关文章

less、sass、webpack(前端工程化)

目录 一、Less 1.配置less环境 1.先要安装node&#xff1a;在cmd中&#xff1a;node -v检查是否安装node 2.安装less :cnpm install -g less 3.检查less是否安装成功&#xff1a;lessc -v 4.安装成功后&#xff0c;在工作区创建xx.less文件 5.在控制台编译less,命令&…

Spring Cloud——流监控Dashboard

一、编写三个module 1. springcloud-consumer-hystrix-dashboard 1.导入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId><version>1.4.6.RELEASE</version>…

【服务器数据恢复】raid5磁盘阵列硬盘离线的数据恢复案例

服务器数据恢复环境&#xff1a; 某公司一台服务器组建了一组raid5磁盘阵列&#xff0c;作为共享存储池使用。该服务器存储数据库文件和普通文件。 服务器故障&检测&#xff1a; RAID5磁盘阵列的硬盘掉线导致服务器操作系统识别不到D分区。管理员重启了服务器&#xff0c;服…

如何发布新闻稿,包含编写新闻稿、发布渠道

发布新闻稿是一种重要的传播方式&#xff0c;它可以让公众了解你的新闻&#xff0c;并提高新闻的知名度和可信度。在这篇文章中&#xff0c;我将详细介绍如何发布新闻稿&#xff0c;包括选择发布渠道、编写新闻稿、发布新闻稿和推广新闻稿等方面的内容。1、选择发布渠道在发布新…

VirtualBox压缩VDI文件 VDI文件瘦身方法(cenos7)

virtualbox虚拟机运行久了之后就会发现&#xff0c;磁盘镜像vdi文件越来越大。即使你把虚拟机中的大文件删除&#xff0c;这个vdi文件占用的空间还是不变。也就是说动态扩展的vdi文件只会大&#xff0c;不会小。那么大的文件对于备份和分享都不是很方便&#xff0c;所以有必要的…

Arduino-抢答器

抢答器实验实验器件&#xff1a;■ 按键开关&#xff1a;4 个■ 红色LED灯&#xff1a;1 个■ 黄色LED灯&#xff1a;1 个■ 绿色LED灯&#xff1a;1 个■ 220欧电阻&#xff1a;7 个■ 面包板&#xff1a;1 个■ 多彩杜邦线&#xff1a;若干实验连线将代码上传到开发板。程序代…

mysql 学习、复习资料整理详细

mysql 学习、复习资料整理详细1、数据库基础1.1 数据库设计遵循的原则1.2 数据库范式1.2 数据库完整性的实现2、mysql特点3、事务3.1 事务的四大特性 – ACID3.2 并发事务问题3.3 事务的四大隔离级别3.4 事务隔离级别操作sql3.5 事务原理 – LBCC MVCC3.4.1 行的隐藏列3.4.2 Re…

一文教你玩转 Apache Doris 分区分桶新功能|新版本揭秘

数据分片&#xff08;Sharding&#xff09;是分布式数据库分而治之 (Divide And Conquer) 这一设计思想的体现。过去的单机数据库在大数据量下往往面临存储和 IO 的限制&#xff0c;而分布式数据库则通过数据划分的规则&#xff0c;将数据打散分布至不同的机器或节点上&#xf…

【7/101】101次面试之测试技术面试题

01、什么是兼容性测试&#xff1f;兼容性测试侧重哪些方面&#xff1f;答&#xff1a;兼容性测试是一种软件测试类型&#xff0c;它的主要目的是确保一个应用程序在不同的操作系统、不同的浏览器、不同的设备、不同的网络环境等各种环境下能够正常运行&#xff0c;并且不会产生…

Vue使用ElementUI对表单元素进行自定义校验

前言 在使用ElementUI的表单元素时候&#xff0c;除了做一些简单的非空处理校验&#xff0c;在一些特殊的场合&#xff0c;还需要我们做一些自定义校验。 其实ElementUI不仅提供了基本的非空校验&#xff0c;也对我们提供了自定义检验。 在使用的时候还是遇到了一些坑&#…

华为OD机试 - 特异性双端队列(C++) | 附带编码思路 【2023】

刷算法题之前必看 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12199283.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 华为OD机试题…

SAP中BOM基础数量及组件数量单位比例关系的注意事项

下图是BOM展开功能CS11在正式系统和测试系统的截图。从截图中的对比不难看出&#xff0c;最下级的原材料A20981-110在组件的数量为1&#xff0c;实际按BOM中的设定比例折算&#xff0c;应该是1个成品&#xff0c;对应需要0.125件原材料。但这里显示的并不是0.125PC&#xff0c;…

Ubuntu22.04 安装Mongodb6.X

Ubuntu22.04 安装Mongodb6.X 1、Mongodb简介 1.1 什么是MongoDB? Mongodb是一个跨平台的面向文档的NoSQL数据库。它使用带有可选模式的类似JSON的BSON来存储数据。应用程序可以以JSON格式检索信息。 1.2 MongoDB的优点 可以快速开发web型应用&#xff0c;因为灵活&#xff0c;…

sympy高斯光束模型

文章目录Gauss模型sympy封装实战sympy.phisics.optics.gaussopt集成了高斯光学中的常见对象&#xff0c;包括光线和光学元件等&#xff0c;有了这些东西&#xff0c;就可以制作一个光学仿真系统。Gauss模型 高斯光束的基本模型为 E(r,z)E0ω0ω(z)exp⁡[−r2ω2(z)]exp⁡[−ik…

自动增长配置不合理导致的性能抖动

背景客户收到了SQL专家云告警邮件&#xff0c;在凌晨2点到3点之间带有资源等待的会话数暴增&#xff0c;请我们协助分析。现象登录SQL专家云&#xff0c;进入活动会话的趋势分析页面&#xff0c;下钻到2点钟一个小时内的数据&#xff0c;看到每分钟的等待数都在100左右&#xf…

“源启”新程,共筑数字新基石 2023年中电金信跑出转型发展加速度

核心提示 预计到2025年&#xff0c;我国数字经济规模将超60万亿元&#xff0c;我国数字经济投入产出效率将提升至约3.5。 近日&#xff0c;中国信通院数字经济与工业经济领域主席孙克在相关活动中表示&#xff0c;预计到2025年&#xff0c;我国数字经济规模将超60万亿元&#…

2023年华为HCIE-Dacom认证题库(H12-891)

1、如图所示是某位网络工程师在排查OSPF故障时的输出信息。据此判断&#xff0c;以下哪种原因可能导致邻接关系无法正常建立。 Hello报文发送时间不一致认证密码不一致接口的IP地址掩码不一致区域类型不一致 正确答案&#xff1a;C 2、如图所示&#xff0c;路由器的所有接口开启…

极市打榜|未戴鸭舌帽识别算法上线,单人独享1000元合作金

极市打榜 算法打榜是极市平台推出的一种算法项目合作模式&#xff0c;至今已上线 100 产业端落地算法项目&#xff0c;已对接智慧城市、智慧工地、明厨亮灶等多个行业真实需求&#xff0c;算法方向涵盖目标检测、行为识别、图像分割、视频理解、目标跟踪、OCR等。 开发者报名…

学习系统编程No.4【环境变量】

引言&#xff1a; 北京时间&#xff1a;2023/2/20/22:15&#xff0c;昨天晚上&#xff0c;看了一晚上的cs&#xff1a;go&#xff0c;主要原因是因为我的好舍友&#xff0c;叫我开箱子&#xff0c;然后就不可言语&#xff0c;看了一晚上的开箱子和精彩剪辑&#xff0c;不过这个…

携手同心,三阳开泰:读懂2023华为中国政企合作伙伴政策

导语&#xff1a; 《周易》中&#xff0c;把连在一起的爻称为阳爻&#xff0c;乾下坤上&#xff0c;三个阳爻组合在一起&#xff0c;就是泰卦。这也就是“三阳开泰”这个成语的由来&#xff0c;其中“泰”字&#xff0c;代表着冬去春来&#xff0c;有吉亨之象&#xff0c;既象征…