nacos源码服务注册

nacos服务注册

  • 序言
  • 1.源码环境搭建
    • 1.1idea运行源码
    • 1.2 登录nacos
  • 2.服务注册分析
    • 2.1 客户端
      • 2.1.1容器启动监听
      • 2.1.2注册前初始化
      • 2.1.3注册服务
    • 2.2 服务端
      • 2.2.1注册
      • 2.2.2重试机制
  • 3.注意事项

序言

本文章是分析的是nacos版本2.2
这次版本是一次重大升级优化,由原来(临时服务)服务注册tcp改成grpc方式,减少资源消耗,服务推送由udp也改为grpc

1.源码环境搭建

  • 源码下载

1.1idea运行源码

  • 导入
  • clean-install-reimport
    在这里插入图片描述
  • 配置
    在这里插入图片描述
  • 启动
    单机运行 启动项配置 VM option
    在这里插入图片描述

1.2 登录nacos

在这里插入图片描述

2.服务注册分析

2.1 客户端

首先让我去实现一个服务注册,我们如何去做?
思考一:
是不是项目启动的时候进行服务注册
思考二:
springboot自动装载,是不是引入nacos依赖,就可以实现服务注册功能

按照上面的思路去分析注册大概过程就很清晰了

2.1.1容器启动监听

  • 自动加载入口
 @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
        return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);
    }
    
 public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
        super(serviceRegistry, autoServiceRegistrationProperties);
        this.registration = registration;
    }
  • web容器监听
public abstract class AbstractAutoServiceRegistration<R extends Registration> implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {

  • 綁定事件
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.bind(event);
    }

    /** @deprecated */
    @Deprecated
    public void bind(WebServerInitializedEvent event) {
        ApplicationContext context = event.getApplicationContext();
        if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
            this.port.compareAndSet(0, event.getWebServer().getPort());
            this.start();
        }
    }
  public void start() {
        if (!this.isEnabled()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Discovery Lifecycle disabled. Not starting");
            }

        } else {
            if (!this.running.get()) {
                this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
                this.register();
                if (this.shouldRegisterManagement()) {
                    this.registerManagement();
                }

                this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
                this.running.compareAndSet(false, true);
            }

        }
    }

2.1.2注册前初始化

  • 获取namingservice服务
 public void register(Registration registration) {
       //创建namingservice服务
       NamingService namingService = this.namingService();
       //注册
       namingService.registerInstance(serviceId, group, instance);  
    }
  • 判断服务是否存在
  public NamingService getNamingService() {
        //不存在进行创建
        if (Objects.isNull(this.namingService)) {
            this.buildNamingService(this.nacosDiscoveryProperties.getNacosProperties());
        }

        return this.namingService;
    }
  • 创建NamingService服务
 NamingService naming = NamingFactory.createNamingService(properties);
 public NacosNamingService(Properties properties) throws NacosException {
        //nacosNamingService 客户端初始化
        init(properties);
    }
    
    private void init(Properties properties) throws NacosException {
        final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
        
        ValidatorUtils.checkInitParam(nacosClientProperties);
        //获取命名空间
        this.namespace = InitUtils.initNamespaceForNaming(nacosClientProperties);
        InitUtils.initSerialization();
        InitUtils.initWebRootContext(nacosClientProperties);
        initLogName(nacosClientProperties);
        //通知时间范围
        this.notifierEventScope = UUID.randomUUID().toString();
        //改变消息通知者
        this.changeNotifier = new InstancesChangeNotifier(this.notifierEventScope);
        //消息中心注册事件
        NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384);
        //注册订阅者
        NotifyCenter.registerSubscriber(changeNotifier);
        //服务信息持有者
        this.serviceInfoHolder = new ServiceInfoHolder(namespace, this.notifierEventScope, nacosClientProperties);
        //创建客户端代理 去委托NamingClientProxyDelegate
        this.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, nacosClientProperties, changeNotifier);
    }

2.1.3注册服务

   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);
    }
 public void doRegisterService(String serviceName, String groupName, Instance instance) throws NacosException {
        InstanceRequest request = new InstanceRequest(namespaceId, serviceName, groupName,
                NamingRemoteConstants.REGISTER_INSTANCE, instance);
        //请求注册
        requestToServer(request, Response.class);
        //设置缓存数据状态为已经注册状态
        redoService.instanceRegistered(serviceName, groupName);
    }

2.2 服务端

2.2.1注册

    private InstanceResponse registerInstance(Service service, InstanceRequest request, RequestMeta meta)
            throws NacosException {
        clientOperationService.registerInstance(service, request.getInstance(), meta.getConnectionId());
        NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(),
                meta.getClientIp(), true, service.getNamespace(), service.getGroup(), service.getName(),
                request.getInstance().getIp(), request.getInstance().getPort()));
        return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);
    }
    @Override
    public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {
        NamingUtils.checkInstanceIsLegal(instance);
        //获取当前的 Service (没有就新创建)
        Service singleton = ServiceManager.getInstance().getSingleton(service);
        if (!singleton.isEphemeral()) {
            throw new NacosRuntimeException(NacosException.INVALID_PARAM,
                    String.format("Current service %s is persistent service, can't register ephemeral instance.",
                            singleton.getGroupedServiceName()));
        }
        Client client = clientManager.getClient(clientId);
        if (!clientIsLegal(client, clientId)) {
            return;
        }
        InstancePublishInfo instanceInfo = getPublishInfo(instance);
        client.addServiceInstance(singleton, instanceInfo);
        client.setLastUpdatedTime();
        client.recalculateRevision();
        // 发布通知注册时间
        NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
        NotifyCenter
                .publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));
    }
    

2.2.2重试机制

为了确保注册成功,会从缓存中,把注册状态为失败的注册实例进行重新注册

   public NamingGrpcRedoService(NamingGrpcClientProxy clientProxy) {
        this.redoExecutor = new ScheduledThreadPoolExecutor(REDO_THREAD, new NameThreadFactory(REDO_THREAD_NAME));
        this.redoExecutor.scheduleWithFixedDelay(new RedoScheduledTask(clientProxy, this), DEFAULT_REDO_DELAY,
                DEFAULT_REDO_DELAY, TimeUnit.MILLISECONDS);
    }
    public void run() {
        if (!redoService.isConnected()) {
            LogUtils.NAMING_LOGGER.warn("Grpc Connection is disconnect, skip current redo task");
            return;
        }
        try {
            //重新注册
            redoForInstances();
            //重新订阅
            redoForSubscribes();
        } catch (Exception e) {
            LogUtils.NAMING_LOGGER.warn("Redo task run with unexpected exception: ", e);
        }
    }

3.注意事项

  • idea 运行源码找不到类
    这时,你需要clean 再install 最后reimport,就不会问题
    在这里插入图片描述

  • 启动时nacos没有以单例模式启动也会报错

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

浅析DNS Rebinding

0x01 攻击简介 DNS Rebinding也叫做DNS重绑定攻击或者DNS重定向攻击。在这种攻击中&#xff0c;恶意网页会导致访问者运行客户端脚本&#xff0c;攻击网络上其他地方的计算机。 在介绍DNS Rebinding攻击机制之前我们先了解一下Web同源策略&#xff0c; Web同源策略 同源策略…

微前端--qiankun原理概述

demo放最后了。。。 一、微前端 一》微前端概述 微前端概念是从微服务概念扩展而来的&#xff0c;摒弃大型单体方式&#xff0c;将前端整体分解为小而简单的块&#xff0c;这些块可以独立开发、测试和部署&#xff0c;同时仍然聚合为一个产品出现在客户面前。可以理解微前端是…

【从零开始学Skynet】基础篇(八):简易留言板

这一篇我们要把网络编程和数据库操作结合起来&#xff0c;实现一个简单的留言板功能。 1、功能需求 如下图所示&#xff0c;客户端发送“set XXX”命令时&#xff0c;程序会把留 言“XXX”存入数据库&#xff0c;发送“get”命令时&#xff0c;程序会把整个留言板返回给客户端。…

HarmonyOS/OpenHarmony应用开发-Stage模型ArkTS语言Ability基类

Ability模块提供对Ability生命周期、上下文环境等调用管理的能力&#xff0c;包括Ability创建、销毁、转储客户端信息等。 说明: 模块首批接口从API version 9 开始支持。模块接口仅可在Stage模型下使用。 导入模块: import Ability from ohos.app.ability.Ability; 接口说明…

如何利用python机器学习解决空间模拟与时间预测问题及经典案例分析

目录 专题一 机器学习原理与概述 专题二 Python编译工具组合安装教程 专题三 掌握Python语法及常见科学计算方法 专题四 机器学习数据清洗 专题五 机器学习与深度学习方法 专题六 机器学习空间模拟实践操作 专题七 机器学习时间预测实践操作 更多 了解机器学习的发展历…

NVIDIA- cuSPARSE(四)

cuSPARSE logging 日志记录机制&#xff0c; 可以通过在启动目标应用程序之前设置一下环境变量来启动cuSPARSE日志记录机制&#xff1a; CUSPARSE_LOG_LEVEL<level> level的取值&#xff1a; 0 Off 日志记录关闭1 Error只有报错会被记录2Trace启动CUDA内核的API调用将记…

配置基于WSL2的Docker环境并支持CUDA

导言 Content 正如前文windows 10 开启WSL2介绍的&#xff0c;我们可以在windows10中使用linux子系统。今天本文介绍如何在此基础上安装Docker并支持在wsl中使用GPU。 准备工作 加入windows insider preview。建议选Dev通道&#xff0c;不要选Beta。 安装Nvidia WSL2-compa…

docker too many open files解决方式

1&#xff1a;问题描述 今天在环境上执行docker ps命令失败&#xff0c;如下提示 [rootcontrol02 ~]# docker ps -a lgrep nginx Cannot connect to the Docker daemon at unix:///var/run/docker.sock, Is the docker daemon running?2&#xff1a;查看节点docker状态 看信…

云原生网络之微隔离

本博客地址&#xff1a;https://security.blog.csdn.net/article/details/130044619 一、微隔离介绍 1.1、微隔离概念 在主体执行动作时&#xff0c;对主体权限和行为进行判断&#xff0c;最常见的是网络访问控制&#xff0c;也就是零信任网络访问&#xff08;ZTNA&#xff…

图片怎么转换成pdf格式?这几个方法帮你一键转换

现今电子书籍越来越受到欢迎&#xff0c;其中PDF格式也成为了一种常用的电子书籍格式。无论是工作还是学习&#xff0c;我们都可能会遇到需要将图片转换成PDF格式的情况&#xff0c;例如保存一些资料证明、公文公告、学习资料等。在这篇文章中&#xff0c;我们将为大家介绍三种…

IO多路复用机制详解

高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型&#xff0c;常见的IO模型有四种&#xff1a; &#xff08;1&#xff09;同步阻塞IO&#xff08;Blocking IO&#xff09;&#xff1a;即传统的IO模型。 &#xff08;2&#xff09;同步非阻塞IO&#xff08;Non-blo…

【权限维持】黄金白银票据隐藏账户C2远控RustDeskGotoHTTP

文章目录内网域&单机版-权限维持-基于用户-隐藏用户内网域-权限维持-基于服务TGT-黄金白银票据黄金方法&#xff1a;白银方法&#xff1a;内网域-权限维持-基于软件-GotoHTTP&RustDesk—无需安装C2 GotoHTTPC2 RustDesk 推荐内网域&单机版-权限维持-基于用户-隐藏用…

研究生,但是一直在摆烂学不进去

好的&#xff0c;我来为您创作一首歌曲&#xff0c;希望能够帮助您每天保持自律&#xff0c;专注学习。 《自律之歌》 第1节&#xff1a; 每天都要努力 学习不停歇 独自一人也要坚持 不放弃自己的梦想 读文献 写论文 我们不停探索 穷孩子的荣耀 就在不远处等候 合唱&#xf…

仿京东放大镜效果的实现

仿京东放大镜 &#xff08;1&#xff09; 整个案例可以分为三个功能模块 &#xff08;2&#xff09; 鼠标经过小图片盒子&#xff0c; 黄色的遮挡层 和 大图片盒子显示&#xff0c;离开隐藏2个盒子功能 &#xff08;3&#xff09;黄色的遮挡层跟随鼠标功能。 &#xff08;4&…

Dapr微服务

** 一、Dapr是什么 ** 官方解释&#xff1a;Dapr (Distributed Application Runtime)是一个可移植的、事件驱动的运行时 可移植&#xff1a;指与软件从某一环境转移到另一环境下的难易程度。事件驱动&#xff1a;调用与被调用方解耦 自己理解&#xff1a;Dapr为任何语言编写…

【通过Cpython3.9源码看看列表到底是咋回事】

列表结构 typedef struct {PyObject_VAR_HEAD/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */PyObject **ob_item;/* ob_item contains space for allocated elements. The number* currently in use is ob_size.* Invariants:* 0 < ob_siz…

Matlab论文插图绘制模板第85期—模值赋色的箭头图

在之前的文章中&#xff0c;分享了Matlab箭头图的绘制模板&#xff1a; 进一步&#xff0c;如果我们想对每一个箭头赋上颜色&#xff0c;以更加直观地表示其模值的大小&#xff0c;该怎么操作呢&#xff1f; 那么&#xff0c;来看一下模值赋色的箭头图的绘制模板。 先来看一下…

老胡的周刊(第086期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。&#x1f3af; 项目MochiDiffusion[2]在 MacOS 上运行原生的 Stab…

游戏解密之常见网络游戏同步方式分析

一、为什么需要有同步呢&#xff1f; 同步机制是用来维护游戏的一致性&#xff0c;通俗的说就是虚拟世界中的事实&#xff1b;比如在CF中&#xff0c;大家的PING都很高&#xff0c;A和B两个玩家同时发现了对方&#xff0c;并向对方开火&#xff0c;如果没有很好的同步机制&…

【学习笔记】滑动窗口

acwing.滑动窗口https://www.acwing.com/problem/content/156/ 给定一个大小为 n≤106≤106 的数组。 有一个大小为 k 的滑动窗口&#xff0c;它从数组的最左边移动到最右边。 你只能在窗口中看到 k 个数字。 每次滑动窗口向右移动一个位置。 以下是一个例子&#xff1a; …