Nacos 解读:服务发现客户端
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的几个核心类及其关系如下图。我们分别来看一下这几个类。
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 |
返回示例:ok
注销实例
| key | 含义 | 备注 |
|---|---|---|
| namespaceId | 命名空间 | 默认为public |
| ip | 实例IP地址 | |
| port | 实例端口 | |
| serviceName | 服务名 | |
| clusterName | 集群名 | 默认为DEFAULT |
返回示例:ok
获取实例列表
| key | 含义 | 备注 |
|---|---|---|
| namespaceId | 命名空间 | 默认为public |
| serviceName | 服务名 | |
| clusters | 集群名 | 默认为DEFAULT |
| udpPort | 监听的UPD端口号 | 由PushReceiver创建 |
| clientIP | 客户端IP | |
| healthyOnly | 是否只返回健康的实例 |
返回示例:{“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用来标识状态的 |
返回示例:{“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 | 过滤器 |
返回示例:{“count”:1,”doms”:[“nacos.test.3”]}
结语
Nacos服务发现的客户端较为简单,其他语言也可以参照其API来实现客户端。如果对源码实现感兴趣,可以自己看下代码。
Nacos 解读:服务发现客户端的更多相关文章
- 聊一聊Yarp结合Nacos完成服务发现
背景 Yarp 这个反向代理出来后,相信还是有不少人在关注的. 在 Yarp 中,反向代理的配置默认也是基于配置文件的,也有不少大佬已经把这个配置做成了数据库配置+可视化界面. 仔细想了想,做成数据库 ...
- Docker安装Nacos动态服务发现、配置和服务管理平台
一.通过DockerHub拉镜像,版本查看:https://github.com/nacos-group/nacos-docker //稳定版,有权限 docker pull nacos/nacos- ...
- 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 ...
- 配置中心Nacos(服务发现)
服务演变之路 单体应用架构 在刚开始的时候,企业的用户量.数据量规模都⽐较⼩,项⽬所有的功能模块都放在⼀个⼯程中编码.编译.打包并且部署在⼀个Tomcat容器中的架构模式就是单体应用架构,这样的架构既 ...
- SpringBoot使用Nacos服务发现
本文介绍SpringBoot应用使用Nacos服务发现. 上一篇文章介绍了SpringBoot使用Nacos做配置中心,本文介绍SpringBoot使用Nacos做服务发现. 1.Eureka闭源 相 ...
- ASP.NET Core结合Nacos来完成配置管理和服务发现
目录 前言 Nacos的简介 启动Nacos 配置管理 服务发现 写在最后 前言 今年4月份的时候,和平台组的同事一起调研了一下Nacos,也就在那个时候写了.net core版本的非官方版的SDK. ...
- .net5+nacos+ocelot 配置中心和服务发现实现
最近一段时间 因公司业务需要,需要使用.net5做一套微服务的接口,使用nacos 做注册中心和配置中心,ocelot做网关. 因为ocelot 支持的是consol和eureka,如果使用nacos ...
- 【笔记】 springCloud--Alibaba--服务注册和服务发现
接着上一次的nacos初步讲解和安装 任意门:https://www.cnblogs.com/Yangbuyi/p/13479767.html 如果启动失败的话 上一篇也是讲解过的. 本文章开始服务注 ...
- Consul 服务发现和配置
Service discovery and configuration made easy. Distributed, highly available, and datacenter-aware. ...
随机推荐
- 小米笔记本pro 黑苹果系统无法进入系统,频繁重启故障解决记录
问题1:频繁重启,然后clover丢失 表现情况:开机没有选择macos 或windos的界面 解决办法:进入windows使用工具easyefi,直接添加一个clover start boot,选择 ...
- JQuery插件 aos.js-添加动画效果
原文地址:http://www.mamicode.com/info-detail-1785357.html 简介: aos.js是一款效果超赞的页面滚动元素动画jQuery动画库插件.该动画库可以在页 ...
- 基于cephfs搭建高可用分布式存储并mount到本地
原文:https://www.fullstackmemo.com/2018/10/11/cephfs-ha-mount-storage/ 服务器硬件配置及环境 项目 说明 CPU 1核 内存 1GB ...
- SpringCloud的阿里巴巴相关开源组件
Sentinel 阿里巴巴开源产品,把流量作为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. Nacos 阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现.配置管理和服 ...
- 【maven】搭建maven私服--基于CentOS7.6+docker
一.docker环境 Docker version 19.03.5, build 633a0ea 二.安装并启动 Maven 私服的工具: Sonatype Nexus 1.搜索 2.下载镜像 doc ...
- 实战讲解XXE漏洞的利用与防御策略
现在许多不同的客户端技术都可以使用XMl向业务应用程序发送消息,为了使应用程序使用自定义的XML消息,应用程序必须先去解析XML文档,并且检查XML格式是否正确.当解析器允许XML外部实体解析时,就会 ...
- linux用户和权限 setuid
uid_t getuid(void); uid_t geteuid(void); int setuid(uid_t uid); int seteuid(uid_t euid); int setegid ...
- swift(三)字典数组操作
//1.数组的概念和定义 var array = [,,,] var array1:Array = [,,,] var array2:Array<Int> = [,,,]; var arr ...
- Mysql Join-连接查询(上)
认识 多表连接查询,我感觉应该是关系型数据库最能体现其价值和灵活性的地方吧. 我觉得数据库的作用, 归纳起来无非就是存储和查询. 一言蔽之,数据库就是能灵活地存储和查询数据. 存储上, 也是以文件的方 ...
- windows elasticsearch使用ik分词器插件后启动报错java.security.AccessControlException: access denied ("java.io.FilePermission" "D:...........\plugins\ik-analyzer\config\IKAnalyzer.cfg.xml" "read")
删除es安装文件夹中空格,遂解决......(哭