Nacos是阿里巴巴的微服务开源项目,用于服务发现和配置管理,开源以来我就一直关注,在此准备以几篇文章来窥其全貌,但大段大段贴代码就没必要了,这里用自己的一些理解和总结来帮助大家理解。文章将基于截止目前最新发布的0.8版本,Nacos的使用方式参考官方文档即可,这里主要从原理和实现上来讲。

Nacos可以分为服务发现(Naming)和配置管理(Config)两块,而从使用上来说,又可分为Nacos服务端和客户端,第一篇先来聊下服务发现(Naming)的客户端。

Example

我们从官方示例入手。

Properties properties = new Properties();
properties.setProperty("serverAddr", System.getProperty("serverAddr"));
properties.setProperty("namespace", System.getProperty("namespace")); NamingService naming = NamingFactory.createNamingService(properties); naming.registerInstance("nacos.test.3", "11.11.11.11", 8888, "TEST1"); naming.registerInstance("nacos.test.3", "2.2.2.2", 9999, "DEFAULT"); System.out.println(naming.getAllInstances("nacos.test.3")); naming.deregisterInstance("nacos.test.3", "2.2.2.2", 9999, "DEFAULT"); System.out.println(naming.getAllInstances("nacos.test.3")); naming.subscribe("nacos.test.3", new EventListener() {
@Override
public void onEvent(Event event) {
System.out.println(((NamingEvent)event).getServiceName());
System.out.println(((NamingEvent)event).getInstances());
}
});

NamingService

从官方示例可以了解到,对于我们使用者来说,NamingService是Nacos对外提供给使用者的接口,其实现类为com.alibaba.nacos.client.naming.NacosNamingService,归纳起来,NamingService提供了以下方法:

  • registerInstance:注册实例。
  • deregisterInstance:注销实例。
  • getAllInstances:获取某一服务的所有实例。
  • selectInstances:获取某一服务健康或不健康的实例。
  • selectOneHealthyInstance:根据权重选择一个健康的实例。
  • getServerStatus:检测服务端健康状态。
  • subscribe:注册对某个服务的监听。
  • unsubscribe:注销对某个服务的监听。
  • getSubscribeServices:获取被监听的服务。
  • getServicesOfServer:获取命名空间(namespace)下的所有服务名。【注:此方法有个小坑,参数pageNo要从1开始】

核心类

Naming Client的几个核心类及其关系如下图。我们分别来看一下这几个类。

 

core-class

NacosNamingService

NacosNamingService是NamingService接口的实现类。实现了上面提到的那些方法。
此外,NacosNamingService还起到了初始化其他核心类的作用,因为对外提供的方法都是委托给其他核心类处理的。按顺序将依次初始化EventDispatcher、NamingProxy、BeatReactor、HostReactor。
从NacosNamingService的构造函数我们也可以了解到,可以进行一些参数的自定义,总结如下(部分概念的含义可参考官方文档):

EventDispatcher

EventDispatcher与其他事件分发的组件没什么不同,用于处理subscribe、unsubscribe等等与服务监听相关的方法,并分发NamingEvent到各Listener。
成员变量ConcurrentMap<String, List<EventListener>> observerMap保存了注册的Listener,key为{服务名}@@{集群名},value为各个EventListener的列表。
EventDispatcher会启动1个名为com.alibaba.nacos.naming.client.listener的线程用于处理事件的分发。

注意点:

  • 分发NamingEvent时,按照subscribe(…)方法的调用顺序串行依次调用EventListener的onEvent(…)方法。
  • 调用subscribe(…)方法会引起对应Service的事件分发。

NamingProxy

NamingProxy用于与Nacos服务端通信,注册服务、注销服务、发送心跳等都经由NamingProxy来请求服务端。
NamingProxy会启动1个名为com.alibaba.nacos.client.naming.serverlist.updater的线程,用于定期调用refreshSrvIfNeed()方法更新Nacos服务端地址,默认间隔为30秒
对服务端API的调用将在后文总结。

注意点:refreshSrvIfNeed()方法对Nacos服务端地址的更新仅在使用endpoint的时候才会进行实际更新,如果是通过serverAddr配置的Nacos服务端地址,refreshSrvIfNeed()方法将不会进行任何操作。

BeatReactor

BeatReactor用于向Nacos服务端发送已注册服务的心跳。
成员变量Map<String, BeatInfo> dom2Beat中保存了需要发送的BeatInfo,key为{serviceName}#{ip}#{port},value为对应的BeatInfo。
BeatReactor会启动名为com.alibaba.nacos.naming.beat.sender的线程来发送心跳,默认线程数为1~CPU核心数的一半,可由namingClientBeatThreadCount参数指定。
默认情况下每5秒发送一次心跳,可根据Nacos服务端返回的clientBeatInterval的值调整心跳间隔。

注意点:0.8版本有一个小bug,客户端心跳间隔并不受服务端返回值的控制。我已提交PR,预计将在0.9版本修复。

HostReactor

HostReactor用于获取、保存、更新各Service实例信息。
成员变量Map<String, ServiceInfo> serviceInfoMap中保存了已获取到的服务的信息,key为{服务名}@@{集群名}。
HostReactor会启动名为com.alibaba.nacos.client.naming.updater的线程来更新服务信息,默认线程数为1~CPU核心数的一半,可由namingPollingThreadCount参数指定。定时任务UpdateTask会根据服务的cacheMillis值定时更新服务信息,默认值为10秒。该定时任务会在获取某一服务信息时创建,保存在成员变量Map<String, ScheduledFuture<?>> futureMap中。

其他

PushReceiver

PushReceiver用于接收Nacos服务端的推送,初始化时会创建DatagramSocket使用UDP的方式接收推送。会启动1个名为com.alibaba.nacos.naming.push.receiver的线程。

FailoverReactor

用于故障转移,会启动1个名为com.alibaba.nacos.naming.failover的线程并定时读取名为00-00—000-VIPSRV_FAILOVER_SWITCH-000—00-00的文件,内容为1时表示开启,此时获取服务信息时会返回FailoverReactor缓存的服务信息。

Balancer

根据服务实例的权重挑选一个实例,实现简单的负载均衡。

DiskCache

用于服务信息的持久化。

Naming API

API汇总如下:

Method URI 含义
POST /nacos/v1/ns/instance 注册实例
DELETE /nacos/v1/ns/instance 注销实例
GET /nacos/v1/ns/instance/list 获取实例列表
PUT /nacos/v1/ns/instance/beat 发送心跳
GET /nacos/v1/ns/api/hello Nacos服务端状态
GET /nacos/v1/ns/service/list 获取所有服务名

参数列表及示例

注册实例

key 含义 备注
namespaceId 命名空间 默认为public
ip 实例IP地址  
port 实例端口  
weight 权重 默认为1.0
enable 是否开启 默认为true
healthy 健康状态 默认为true
metadata 其他信息  
serviceName 服务名  
clusterName 集群名 默认为DEFAULT

请求示例:http://localhost:8848/nacos/v1/ns/instance?metadata=%7B%7D&namespaceId=public&port=8888&enable=true&healthy=true&ip=11.11.11.11&clusterName=TEST1&weight=1.0&serviceName=nacos.test.3&encoding=UTF-8&

返回示例:ok

注销实例

key 含义 备注
namespaceId 命名空间 默认为public
ip 实例IP地址  
port 实例端口  
serviceName 服务名  
clusterName 集群名 默认为DEFAULT

请求示例:http://localhost:8848/nacos/v1/ns/instance?cluster=DEFAULT&serviceName=nacos.test.3&encoding=UTF-8&namespaceId=public&port=9999&ip=2.2.2.2&

返回示例:ok

获取实例列表

key 含义 备注
namespaceId 命名空间 默认为public
serviceName 服务名  
clusters 集群名 默认为DEFAULT
udpPort 监听的UPD端口号 由PushReceiver创建
clientIP 客户端IP  
healthyOnly 是否只返回健康的实例

请求示例:http://localhost:8848/nacos/v1/ns/instance/list?healthyOnly=false&namespaceId=public&clientIP=172.16.20.114&serviceName=nacos.test.3&udpPort=53957&encoding=UTF-8&

返回示例:{“metadata”:{},”dom”:”nacos.test.3”,”cacheMillis”:10000,”useSpecifiedURL”:false,”hosts”:[{“valid”:true,”marked”:false,”metadata”:{},”instanceId”:”2.2.2.2#9999#DEFAULT#nacos.test.3”,”port”:9999,”ip”:”2.2.2.2”,”clusterName”:”DEFAULT”,”weight”:1.0,”serviceName”:”nacos.test.3”,”enabled”:true},{“valid”:true,”marked”:false,”metadata”:{},”instanceId”:”11.11.11.11#8888#TEST1#nacos.test.3”,”port”:8888,”ip”:”11.11.11.11”,”clusterName”:”TEST1”,”weight”:1.0,”serviceName”:”nacos.test.3”,”enabled”:true}],”checksum”:”bd1054e6afb8d10730d945d74c4ce4421550584589236”,”lastRefTime”:1550584589236,”env”:””,”clusters”:””}

发送心跳

key 含义 备注
namespaceId 命名空间 默认为public
serviceName 服务名  
beat BeatInfo的JSON字符串

BeatInfo对象结构如下,与Instance对象类似:

field 含义 备注
port 端口  
ip IP地址  
weight 权重  
metadata 其他信息  
serviceName 服务名  
clusterName 集群名  
scheduled 是否心跳中 这个是BeatReactor用来标识状态的

请求示例:http://localhost:8848/nacos/v1/ns/instance/beat?beat=%7B%22cluster%22%3A%22DEFAULT%22%2C%22ip%22%3A%222.2.2.2%22%2C%22metadata%22%3A%7B%7D%2C%22port%22%3A9999%2C%22scheduled%22%3Atrue%2C%22serviceName%22%3A%22nacos.test.3%22%2C%22weight%22%3A1.0%7D&serviceName=nacos.test.3&encoding=UTF-8&namespaceId=public&

返回示例:{“clientBeatInterval”:5000}

Nacos服务端状态

key 含义 备注
namespaceId 命名空间 默认为public

请求示例:http://localhost:8848/nacos/v1/ns/api/hello?encoding=UTF-8&namespaceId=public&

返回示例:{“msg”:”Hello! I am Nacos-Naming and healthy! total services: raft 2, local port:8848”}

获取所有服务名

key 含义 备注
namespaceId 命名空间 默认为public
pageNo 页码 注意从1开始
pageSize 返回数量  
selector 过滤器

请求示例:http://localhost:8848/nacos/v1/ns/service/list?pageSize=100&encoding=UTF-8&namespaceId=public&pageNo=0&

返回示例:{“count”:1,”doms”:[“nacos.test.3”]}

结语

Nacos服务发现的客户端较为简单,其他语言也可以参照其API来实现客户端。如果对源码实现感兴趣,可以自己看下代码。

Nacos 解读:服务发现客户端的更多相关文章

  1. 聊一聊Yarp结合Nacos完成服务发现

    背景 Yarp 这个反向代理出来后,相信还是有不少人在关注的. 在 Yarp 中,反向代理的配置默认也是基于配置文件的,也有不少大佬已经把这个配置做成了数据库配置+可视化界面. 仔细想了想,做成数据库 ...

  2. Docker安装Nacos动态服务发现、配置和服务管理平台

    一.通过DockerHub拉镜像,版本查看:https://github.com/nacos-group/nacos-docker //稳定版,有权限 docker pull nacos/nacos- ...

  3. spring-boot 2.5.4,nacos 作为配置、服务发现中心,Cloud Native Buildpacks 打包镜像,GitLab CI/CD

    spring-boot 2.5.4,nacos 作为配置.服务发现中心,Cloud Native Buildpacks 打包镜像,GitLab CI/CD 本文主要介绍 Java 通过 Cloud N ...

  4. 配置中心Nacos(服务发现)

    服务演变之路 单体应用架构 在刚开始的时候,企业的用户量.数据量规模都⽐较⼩,项⽬所有的功能模块都放在⼀个⼯程中编码.编译.打包并且部署在⼀个Tomcat容器中的架构模式就是单体应用架构,这样的架构既 ...

  5. SpringBoot使用Nacos服务发现

    本文介绍SpringBoot应用使用Nacos服务发现. 上一篇文章介绍了SpringBoot使用Nacos做配置中心,本文介绍SpringBoot使用Nacos做服务发现. 1.Eureka闭源 相 ...

  6. ASP.NET Core结合Nacos来完成配置管理和服务发现

    目录 前言 Nacos的简介 启动Nacos 配置管理 服务发现 写在最后 前言 今年4月份的时候,和平台组的同事一起调研了一下Nacos,也就在那个时候写了.net core版本的非官方版的SDK. ...

  7. .net5+nacos+ocelot 配置中心和服务发现实现

    最近一段时间 因公司业务需要,需要使用.net5做一套微服务的接口,使用nacos 做注册中心和配置中心,ocelot做网关. 因为ocelot 支持的是consol和eureka,如果使用nacos ...

  8. 【笔记】 springCloud--Alibaba--服务注册和服务发现

    接着上一次的nacos初步讲解和安装 任意门:https://www.cnblogs.com/Yangbuyi/p/13479767.html 如果启动失败的话 上一篇也是讲解过的. 本文章开始服务注 ...

  9. Consul 服务发现和配置

    Service discovery and configuration made easy. Distributed, highly available, and datacenter-aware. ...

随机推荐

  1. 【正则】day02

    正则表达式的应用匹配.查找.分割.替换对于普通字符串处理函数和正则表达式字符处理函数,使用的原则:能用普通字符串处理函数处理的,就不要用正则表达式处理. 原因:普通字符串处理函数:效率高.简单.正则表 ...

  2. 机器学习之感知器和线性回归、逻辑回归以及SVM的相互对比

    线性回归是回归模型 感知器.逻辑回归以及SVM是分类模型 线性回归:f(x)=wx+b 感知器:f(x)=sign(wx+b)其中sign是个符号函数,若wx+b>=0取+1,若wx+b< ...

  3. 阿里云cdn缓存设置技巧,不同文件结尾用不同的缓存时间

    https://edu.aliyun.com/lesson_130_1505?spm=5176.10731542.0.0.2ed37dbf42YL6U#_1505

  4. Jenkins自动发送邮件配置及定时构建

    前言 在配置之前,我们需要安装好Jenkins,对于如何安装不在赘述,看我之前一篇安装教程(或者找度娘,教程很多).接下来我们开始详细讲解build运行完成后自动发送邮件和定时自动构建build 系统 ...

  5. 【Java并发专题之二】Java线程基础

    使用线程更好的提高资源利用率,但也会带来上下文切换的消耗,频繁的内核态和用户态的切换消耗,如果代码设计不好,可能弊大于利. 一.线程 进程是分配资源的最小单位,线程是程序执行的最小单位:线程是依附于进 ...

  6. snappy 安装

    1 下载snappywget https://kojipkgs.fedoraproject.org//vol/fedora_koji_archive00/packages/snappy/1.1.0/1 ...

  7. kali渗透综合靶机(十四)--g0rmint靶机

    kali渗透综合靶机(十四)--g0rmint靶机 靶机下载地址:https://www.vulnhub.com/entry/g0rmint-1,214/ 一.主机发现 1.netdiscover - ...

  8. Thread 另类用法,如何执行一段可能死锁/卡死/死循环的代码

    场景与需求 需要执行一段第三方的代码,这段代码可能死锁/卡死/死循环,在超时之后,如果没有结束,则认为任务执行失败,退出执行. 实现方案1:使用 Task 超时 实现方法参考: https://www ...

  9. Lucene BooleanQuery相关算法

    BooleanQuery对两种不同查询场景执行不同的算法: 场景1: 所有的子句都必须满足,而且所有的子句里没有嵌套BooleanQuery. 例: a AND b AND c 上面语句表示要同时包含 ...

  10. BootStrap-treeview 参考

    简要教程 bootstrap-treeview是一款效果非常酷的基于bootstrap的jQuery多级列表树插件.该jQuery插件基于Twitter Bootstrap,以简单和优雅的方式来显示一 ...