献给Nacos小白的一篇好文:注册中心
Posted 云水之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了献给Nacos小白的一篇好文:注册中心相关的知识,希望对你有一定的参考价值。
服务注册中心
随着微服务的发展,出现了各种各样的服务注册与发现组件,市面使用较多的有eureka、consul、etcd、zookeeper以及本篇的主角nacos等。对于这些组件的优缺点及区别,网络上有很多说法,读者可自行网络识别。Nacos是个不错的选择,它是由阿里牵头,当前社区非常活跃,并且支持网关、限流及监控等配套功能可快速集成,同时它也是个动态配置中心,采用java开发,学习门槛相对低些,受众群体也比较大,所以选择Nacos作为服务的注册和配置中心是个不错的选择。
- 简介及环境搭建
- 服务注册及发现
- 数据存放策略
- 使用的一些建议
一、简介及环境搭建
1、简介
Nacos(Dynamic Naming and Configuration Service),顾名思义,na代表注册中心,而co则代表配置中心,s代表服务。Nacos是由阿里开源的服务注册发现与配置中心组件,采用java语言开发,支持单机、集群及多集群模式,支持多数据中心,早些时间是阿里内部项目,经历过大数据量的压力考验,其官网也提供了详细的性能测试报告,以及相关的使用文档说明,方便读者参考学习。需要特别注意的是Nacos是内部网络应用组件,强烈不推荐暴露在公网使用,实际使用时,一般将其部署在内网,或者采用VIP实现虚拟隔离,以保证其使用的安全性,并且生产环境中,必须搭建集群环境以保证高可用。
2、环境搭建
Nacos使用非常简单,前提是需要你安装和配置好jdk或jre环境,然后,按照如下步骤搭建即可,这里以Linux系统为例,以单机模式运行(单机模式适合学习和测试使用,不适合生产环境,后续章节会继续介绍集群环境的搭建),方便讲解和学习。
A、下载软包
下载地址:
https://github.com/alibaba/nacos/releases
进行解压:
$tar -xvf nacos-server-1.4.3.tar.gz
或
$unzip nacos-server-1.4.3.zip
改个名字:
$mv nacos-server-1.4.3 nacos
B、如何运行
$cd nacos/bin
单机模式:
$startup.sh -m standalone
注意:
单机模式仅适用于本地测试或开发,正常上线时必须配置为集群模式。
C、控制台页
访问地址(默认端口8848、默认帐号/密码:nacos/nacos):
http://127.0.0.1:8848/nacos
登录进来的默认页面效果如下:
二、服务注册及发现
所有支持集成nacos的程序均提供了如何快捷注册服务到nacos的配置方式,如:springboot程序中application.yml配置,这里我们也以此种方式讲解nacos作为服务注册中心,其它类型程序可参看官网说明,对应配置即可。当然,nacos亦提供了http方式的开放api接口供使用者调取(目前参考地址如下):
详细信息可自行查看其官网说明。
另外,如果我们使用springboot2.x构建服务并要注入到nacos中,那么需要先引入nacos集成依赖包,如:pom.xml配置如下:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
注意:这里我们使用了com.alibaba.cloud包装组件,其提供了很多便捷的api供我们使用,这里省略了version版本,则下载的依赖包版本自动随着springboot版本下载兼容版本。
1、服务注册
A、通过API注册一个服务
$curl -X POST 'http://192.168.43.156:8848/nacos/v1/ns/
instance?serviceName=ApiTest&ip=192.168.43.156&port=8080'
ps: 服务名、IP地址及端口号为必填,其它可选参数可参照官网。此时注册到nacos的是一个空服务,因为其没有对应的程序或进程存在,所以一般以此种方式注册服务时,建议先将服务实体运行后再调取接口注册,避免健康检测扫描时检测不到对应服务健康状态,而将其剔除。
B、application.yml注册
spring:
application:
name: provider-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
其中server-addr为nacos的服务注册地址127.0.0.1,默认端口8848。服务被注册到默认的保留命名空间(public)中,nacos提供使用一套nacos环境通过namespace来管理多套隔离的服务环境,方便对服务进行隔离和灵活切换,此时注册服务时,需要填写想要注册到的命名空间ID,命名空间如下创建:
不填写命名空间ID时,默认按照UUID格式生成ID,命名空间名字不能重复。下面是将provider-service服务注册到providers空间的配置,需要配置namespace为providers空间ID,如下:
spring:
application:
name: provider-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: c1a176a1-589d-42b5-8eb5-acf734f1c269
为演示跨空间服务隔离效果,这里创建另一个消费者服务client-service,并将其注册到clients命名空间中,该空间的创建方法请参看providers的创建,配置如下:
spring:
application:
name: client-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 184c0159-a2f7-415a-a395-bb48df58ec8a
两个服务注册后效果如下图:
另外,在nacos中也提供了分组概念,默认服务均被注册到DEFAULT_GROUP中,不需要我们指定,不过令人疑惑的是为什么分组不能可视化维护?但是,我们又可以通过配置将服务注册到指定的分组中,并且经过验证得知,同一个namespace不同group的服务间是不能通信的,只有同一个namespace和同一个group才能通信,这分组隔离与命名隔离道理是一样的。
2、服务发现与隔离
nacos中的服务发现主要是通过服务名、分组和命名空间等信息,在nacos存储中寻找想要消费的服务,然后格式转换并返回。这里我们以测试不同命名空间的服务之间调取为例,来演示服务如何发现及跨命名空间服务调取的限制。
上面创建的client-service和provider-service两个服务,他们分属于不同的命名空间,现在我们使用client-service来调取provider-service服务接口,client-service接口如下:
@GetMapping(value = "/test/hello")
public String testHello(@PathVariable String hello)
// 获取指定服务名的多个实例,如果未找到则代表不属于同一个命名空间
List<ServiceInstance> providers = discoveryClient.getInstances("provider-service");
if(CollectionUtils.isEmpty(providers))
return "未找到该服务,欲调取服务与当前服务不在一个命名空间!";
// 实际环境中,为保障服务可用性,服务一般存在多个实例,这里随机取
Integer index = ThreadLocalRandom.current().nextInt(providers.size());
// 构建完整的provider-service服务的接口地址
String url = providers.get(index).getUri() + "/test/" + hello;
// 采用RestTemplate远程调取服务接口并返回结果
return restTemplate.getForObject(url, String.class);
下面是provider-service服务接口,直接返回调取端传递的hello字符串文本,如下:
@GetMapping(value = "/test/hello")
public String hello(@PathVariable String hello)
return hello;
2.1 如何寻找服务
我们在client-service服务中添加如上代码,其中使用了DiscoveryClient,它是个通用的模版接口,而nacos自定义了NacosDiscoveryClient来重写它的getInstances方法,主要通过传递的服务ID或服务名、组名及命名空间(当前服务配置的空间ID)等信息找到服务端信息(实际上最终会通过HttpClient调取nacos开放http接口/instance/list),并转为ServiceInstance服务实例类型供我们使用,这就是如何在nacos中寻找或发现服务。
另外,实际我们在注册服务到nacos时,为了保障服务的高可用性,往往需要为单个服务注册多个实例,所以出现了上面的List<ServiceInstance>来接收同个服务的多个实例,这也是服务负载调度的前提条件。
2.2 跨空间调取限制
了解了发现服务的过程,通过查看源码可知道,我们在调取getInstances并传递服务名时,实际上该方法内会从NacosDiscoveryProperties中获取当前服务client-service所配置的命名空间, 并结合传递的服务名、组名等信息,通过HttpClient调取开放的/instance/list接口,如果查询不到服务信息ServiceInstance,则代表服务不在一个空间,这就是nacos中的命名空间隔离原理。
此时,调取服务provider-service的接口时,直接返回"未找到该服务,欲调取服务与当前服务不在一个命名空间!" 提示信息。我们可以将服务provider-service同样注册到client-service所在的空间时,然后通过RestTemplate访问相关接口,此时就能正常访问,建议读者尝试验证。
三、数据存放策略
我们知道,在nacos中我们可通过服务名字、分组及命名空间等信息,找到服务具体的调取信息,如:IP、端口号、服务名等。那么,这些信息是从哪里获取的?其实也就是要知道服务注册的信息存放在哪里,以及如何存放的。
这里先介绍单机模式,后面再介绍集群模式。注册到nacos的服务实例信息是存放在Map数据结构的内存中,目前nacos使用了ConcurrentSkipListMap,因为我们知道nacos对服务的存储是共享的,所以会存在多个线程并发访问的安全问题,而ConcurrentSkipListMap比较适合解决此类问题,这主要是依靠它的“跳表”存取算法,只需局部加锁,所以吞吐率比较好,这是nacos选择它的主要原因。
那么,都存放哪些服务实例信息了?nacos主要存放了服务所在机器的IP地址和端口号、空间ID、分组Group、服务名字等信息,这也就是前面我们发现服务所需要的一些基本信息。
四、使用的一些建议
1、建议指定服务所归属的命名空间namespace,如果公司的服务测试和生产环境均采用同一套nacos管理的话,那么,就可以创建测试和生产两套命名空间,以便于灵活切换管理。当然,也可以有别的划分维度,比如:按业务块划分或区域划分等,具体要看实际场景需求来定。
2、对于分组的划分,笔者建议从实际角度考虑,如果namespace能够满足隔离需求,可以不设定分组,毕竟少了维护分组的工作。
以上是关于献给Nacos小白的一篇好文:注册中心的主要内容,如果未能解决你的问题,请参考以下文章