Nacos 解读:服务发现客户端

Stella981
• 阅读 202

转载于:https://www.cnblogs.com/lykbk/p/werwerwer35434343434343.html

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的几个核心类及其关系如下图。我们分别来看一下这几个类。

Nacos 解读:服务发现客户端

core-class

NacosNamingService

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

EventDispatcher

EventDispatcher与其他事件分发的组件没什么不同,用于处理subscribe、unsubscribe等等与服务监听相关的方法,并分发NamingEvent到各Listener。
成员变量ConcurrentMap<String, List> 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来实现客户端。如果对源码实现感兴趣,可以自己看下代码。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Stella981 Stella981
1年前
Nacos跨服务器调用服务报错
利用gateway做springcloud微服务网关路由服务时出现报错情况,发现是和网关不在一个服务器的服务无法使用Nacos服务注册的IPNacos注册中心是:https://github.com/alibaba/nacos各个服务通过Nacos客户端将服务信息注册到Nacos上当Nacos服务注册的IP默认选择出问题时,可以通
Stella981 Stella981
1年前
Linux服务器性能查看分析调优
转自https://www.cnblogs.com/acelee/p/6628079.html一linux服务器性能查看1.1cpu性能查看1、查看物理cpu个数:cat/proc/cpuinfo|grep"physicalid"|sort|un
Stella981 Stella981
1年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
1年前
mysql系列(三)——mysql架构与存储引擎
一、MySql逻辑架构!(https://oscimg.oschina.net/oscnet/up35e1824330cd1df7ac66652b9b1dbc41965.png)1.连接层!(https://oscimg.oschina.net/oscnet/up272cb2634e262cc2df52220a063
Stella981 Stella981
1年前
Golang注册Eureka的工具包goeureka发布
1.简介提供Go微服务客户端注册到Eureka中心。点击:github地址(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2FSimonWang00%2Fgoeureka),欢迎各位多多star!(已通过测试验证,用于正式生产部署)2.原理
Stella981 Stella981
1年前
Centos7下ELK+Redis日志分析平台的集群环境部署记录
转载于http://www.cnblogs.com/kevingrace/p/9104423.html之前的文档介绍了ELK架构的基础知识(推荐参考下http://blog.oldboyedu.com/elk/(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fblog.oldboyed
Stella981 Stella981
1年前
Jenkins插件下载镜像加速
转:https://www.cnblogs.com/zhuochong/p/10082498.html可供选择的jenkins2插件镜像列表:Jenkins所有镜像列表:http://mirrors.jenkinsci.org/status.html比如日本的镜像:http://mirror.esuni.jp/jenkins/,ht
Wesley13 Wesley13
1年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Stella981 Stella981
1年前
40个Java多线程问题总结
前言 转自 https://www.cnblogs.com/xrq730/p/5060921.html(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.cnblogs.com%2Fxrq730%2Fp%2F5060921.html)40个问题汇总1