Nacos 是什么?
本文基于: Nacos 1.4.0
-
官方介绍
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
核心特点:
既可以是注册中心也可以是配置中心
-
服务是一等公民
-
服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:
Kubernetes Service
gRPC & Dubbo RPC Service
Spring Cloud RESTful Service
-
-
Nacos 的关键特性包括:
-
服务发现
默认支持服务健康监测
- Nacos 支持基于 DNS 和基于 RPC 的服务发现
-
配置中心
-
默认支持动态配置刷新功能,无需额外配置
- 在Nacos控制台修改了配置后,点击发布时,会自动通知Nacos客户端更新本地缓存的配置文件。如果客户端的某个变量值就来自配置文件那么可以结合 @RefreshScope 注解实现变量值的更新。
动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
Nacos 提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。
-
Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性
,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。NACOS server 会记录配置文件的历史版本,保留30天,同时还贴心的提供了一键回滚功能,回滚操作将会触发配置更新。
-
配置快照(本地)
Nacos 的客户端 SDK 会在本地生成配置的快照。当客户端无法连接到 Nacos Server 时,可以使用配置快照显示系统的整体容灾能力。
-
-
动态 DNS 服务
动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。
Nacos 提供了一些简单的 DNS APIs TODO 帮助您管理服务的关联域名和可用的 IP:PORT 列表.
-
服务及其元数据管理
Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
-
-
Nacos 地图
-
Nacos 概念
-
Nacos 架构
怎么用?
-
文档与代码
Nacos官方Git地址:https://github.com/alibaba/nacos
Nacos官方文档地址:https://nacos.io/zh-cn/docs/
2.1 快速开始 - 安装 Nacos Server
-
2020-08 : 当前推荐的稳定版本为 1.4.0 。
下载源码或者安装包
你可以通过源码和发行包两种方式来获取 Nacos。
-
从 Github 上下载源码方式
git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
ls -al distribution/target/// change the version/nacos/bin
-
下载编译后的压缩包方式
-
您可以从 最新稳定版本 下载 nacos-server-$version.zip 包。
unzip nacos-server-version.tar.gz
cd nacos/bin 解压后可以发现,其实是个 SpringBoot 工程
-
启动服务器
-
Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式):sh startup.sh -m standalone
-
如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:
bash startup.sh -m standalone
-
Windows
启动命令:
cmd startup.cmd
或者双击startup.cmd运行文件。
启动后可以在日志文件后看到
: | \ | : ,--.--. ,---. / / | / / ' Pid: 2423
| : ' '; | / \ / \. ; ,. :| : /`./ Console: http://169.254.212.54:8848/nacos/index.html
' ' ;. ;.--. .-. | / / '' | |: :| : ;_
| | | \ | \__\/: . .. ' / ' | .; : \ \ `. https://nacos.io
' : | ; .' ," .--.; |' ; :__| : | `----. \
| | '`--' / / ,. |' | '.'|\ \ / / /`--' /
' : | ; : .' \ : : `----' '--'. /
; |.' | , .-./\ \ / `--'---'
* 默认用户名密码: nacos/nacos
-
Tips:
- 如果想修改JVM参数,那么直接修改 startup.sh 文件即可。
- 如果想修改 Nacos 的端口: 安装目录: /nacos/conf/application.properties 文件中修改即可
进入控制台
-
Nacos有几个基础概念,我们只有先了解清楚之后才能更好的结合到业务场景:
namespace 命名空间
Group 配置分组
DataID 具体的配置文件名称,例如: application-dev.yml
一般我们使用namespace来区分不同的项目或环境。
不同的 namespace 或者不同的 Group 之间的配置与服务都是隔离的
-
Group 区分配置的差异系比如A业务获取的配置和B团队的有一些细微的差别可以通过Group来区分。
配置分组,建议填写产品名:模块名(Nacos:Test)保证唯一性,只允许英文字符和4种特殊字符("."、":"、"-"、"_"),不超过128字节。
需要在客户端的bootstrap.properties来添加分组信息才能取到非默认组的文件
最后使用DataId来区分具体的配置文件。
一个 DataID 就对应一个配置文件。
-
如果需要使用 Nacos 的配置中心功能
-
首先新建一个命名空间 - 不创建则会使用默认的命名空间(public)
比如: 先创建一个 sms-dev 表示短信平台项目 Dev 环境
目前一个命名空间下最多可以配置 200 个配置文件。
-
在配置管理页面新建一个配置
* DataID : sms-api-service-dev.yaml * Group : DEFAULT_GROUP * 配置格式: YAML * 配置内容: user.name: sms-api-service-dev-yaml user.age: 68
-
注意:注意dataid是以 properties(默认的文件扩展名方式)为扩展名。如果要使用 yml 或者 yaml
-
在应用的 bootstrap.properties 配置文件中显示的声明 dataid 文件扩展名。如下所示
-
bootstrap.properties
spring.cloud.nacos.config.file-extension=yaml
-
-
-
注意: 如果不使用 DEFAULT_GROUP , 则需要在客户端的bootstrap.properties来添加分组信息才能取到非默认组的文件
spring.cloud.nacos.config.group=myGroup1
新建完成后,也有对应的JAVA系的示例代码
-
-
2.2 Nacos Spring Cloud 快速开始
本文主要面向 Spring Cloud 的使用者,通过两个示例来介绍如何使用 Nacos 来实现分布式环境下的配置管理和服务注册发现。
-
关于 Nacos Spring Cloud 的详细文档请参看:Nacos Config 和 Nacos Discovery。
通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-config 实现配置的动态变更。
通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-discovery 实现服务的注册与发现。
-
前提
您需要先下载 Nacos 并启动 Nacos server。
-
使用配置中心
-
客户端依赖
-
parent.xml - 采用公共版本依赖管理的方式
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR4</version> <type>pom</type> <scope>import</scope> </dependency> <dependencyManagement> <dependencies> <!--spring cloud alibaba--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.0.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependencies> <dependencyManagement>
-
my-demo.xml
<!--配置中心客户端--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
注意: 关于 SpringCloudAlibaba 跟 SpringCloud 跟 SpringBoot 的版本是有对照关系的
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
-
-
然后必须配置下面这两个配置项
spring.application.name=nacos-demo # spring.cloud.nacos.config.server-addr :Nacos 服务器的地址和端口 spring.cloud.nacos.config.server-addr=127.0.0.1:8848
-
server-addr 属性
-
代码位置: com.alibaba.nacos.client.config.impl.ServerListManager#ServerListManager(java.util.Properties)
if (StringUtils.isNotEmpty(serverAddrsStr)) { isFixed = true; List<String> serverAddrs = new ArrayList<String>(); String[] serverAddrsArr = serverAddrsStr.split(","); for (String serverAddr: serverAddrsArr) { if (serverAddr.startsWith(HTTPS) || serverAddr.startsWith(HTTP)) { serverAddrs.add(serverAddr); } else { String[] serverAddrArr = serverAddr.split(":"); if (serverAddrArr.length == 1) { serverAddrs.add(HTTP + serverAddrArr[0] + ":" + ParamUtil.getDefaultServerPort()); } else { serverAddrs.add(HTTP + serverAddr); } } } serverUrls = serverAddrs; if (StringUtils.isBlank(namespace)) { name = FIXED_NAME + "-" + getFixedNameSuffix(serverUrls.toArray(new String[serverUrls.size()])); } else { this.namespace = namespace; this.tenant = namespace; name = FIXED_NAME + "-" + getFixedNameSuffix(serverUrls.toArray(new String[serverUrls.size()])) + "-" + namespace; } }
-
从源码可知
实际上是支持配置多个地址的,只需要用 ; 分割。 不具有客户端负载均衡的效果,但是有高可用的效果。
如果配置的某个地址没有带上 ":port" 部分,那么默认会把 8848 作为端口号来拼接。因此在你搭建了NacosVip的情况下,建议让Nginx也监听 8848 端口,或者在你的vip后面补充一个 :80 即可。
-
-
说明:之所以需要配置 spring.application.name ,是因为它是构成 Nacos 配置管理 dataId字段的一部分。
-
在 Nacos Spring Cloud 中,dataId 的完整格式如下:
{spring.profile.active}.${file-extension}
prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix 来配置。
spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profile.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成
{file-extension}file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。
以上面的例两行配置为例: 此时将会加载 nacos 中 默认(public) 命名空间下的, DEFAULT_GROUP 分组下的 DataID 为 nacos-demo.properties 文件。
-
如果需要加载指定命名空间(sms-dev)下非默认分组(MY_GROUP1)下的DataID 为 sms-api-service-dev.yaml 的配置文件
-
bootstrap.yml
spring: application: name: @artifactId@ cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: ${spring.cloud.nacos.discovery.server-addr} file-extension: yaml namespace: sms-dev group: MY_GROUP1 profiles: active: @profiles.active@
-
pom.xml 中配置的 artifactId 为 sms-api-service, rofiles.active 为 dev
- 当然也可以不引用 pom.xml 中的配置。直接在 bootstrap.yml 中写入这两个值。
-
-
-
注意
当你使用域名的方式来访问 Nacos 时,spring.cloud.nacos.config.server-addr 配置的方式为 域名:port。 例如 Nacos 的域名为abc.com.nacos,监听的端口为 80,则 spring.cloud.nacos.config.server-addr=abc.com.nacos:80。 注意 80 端口不能省略。
-
示例: 在SpringBoot中打印配置
public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ProviderApplication.class, args); String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); System.err.println("user name :"+userName+"; age: "+userAge); }
-
-
完全关闭配置
通过设置 spring.cloud.nacos.config.enabled = false 来完全关闭 Spring Cloud Nacos Config
-
-
使用注册中心 - Nacos discovery
-
依赖配置
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
-
pom.xml的配置。一个完整的 pom.xml 配置如下所示:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>open.source.test</groupId> <artifactId>nacos-discovery-test</artifactId> <version>1.0-SNAPSHOT</version> <name>nacos-discovery-test</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring.boot.version}</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring.cloud.alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
-
启动一个 Provider 应用
-
在 bootstrap.properties 中或者 application.properties 中配置
server.port=8081 spring.application.name=nacos-producer spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 # management.endpoints.web.exposure.include=*
-
应用程序启动类添加 @EnableDiscoveryClient 注解。
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderDemoApplication {public static void main(String[] args) { SpringApplication.run(NacosProducerDemoApplication.class, args); } @RestController public class EchoController { @GetMapping(value = "/echo/{string}") public String echo(@PathVariable String string) { return "Hello Nacos Discovery " + string; } }
}
-
-
服务的 EndPoint
spring-cloud-starter-alibaba-nacos-discovery 在实现的时候提供了一个EndPoint,EndPoint的访问地址为 http://ip:port/actuator/nacos-discovery。 EndPoint 的信息主要提供了两类:
- subscribe: 显示了当前有哪些服务订阅者
- NacosDiscoveryProperties: 显示了当前服务实例关于 Nacos 的基础配置
-
启动一个 Consumer 应用
Consumer 的应用可能还没像启动一个 Provider 应用那么简单。因为在 Consumer 端需要去调用 Provider 端提供的REST 服务。例子中我们使用最原始的一种方式, 即显示的使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问。
Note
通过带有负载均衡的RestTemplate 和 FeignClient 也是可以访问的。@SpringBootApplication @EnableDiscoveryClient public class NacosConsumerApp { @RestController public class NacosController{ @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate; @Value("${spring.application.name}") private String appName; @GetMapping("/echo/app-name") public String echoAppName(){ //使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问 ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider"); String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName); System.out.println("request url:"+url); return restTemplate.getForObject(url,String.class); } } //实例化 RestTemplate 实例 @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(NacosConsumerApp.class,args); } }
这个例子中我们注入了一个 LoadBalancerClient 的实例,并且手动的实例化一个 RestTemplate,同时将 spring.application.name 的配置值 注入到应用中来, 目的是调用 Provider 提供的服务时,希望将当前配置的应用名给显示出来。
- Note
在启动 Consumer 应用之前请先将 Nacos 服务启动好。具体启动方式可参考 Nacos 官网。
启动后,访问 Consumer 提供出来的 http://ip:port/echo/app-name 接口。我这里测试启动的 port是 8082。访问结果如下所示:
访问地址:http://127.0.0.1:8082/echo/app-name 访问结果:Hello Nacos Discovery nacos-consumer
- Note
-
关于 Nacos Starter 更多的配置项信息
-
例如:
集群 spring.cloud.nacos.discovery.cluster-name DEFAULT 配置成Nacos集群名称
AccessKey spring.cloud.nacos.discovery.access-key 无 当要上阿里云时,阿里云上面的一个云账号名
是否开启Nacos Watch spring.cloud.nacos.discovery.watch.enabled true 可以设置成false来关闭 watch
命名空间 spring.cloud.nacos.discovery.namespace 无 常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等
-
-
Note
- 如果不想使用 Nacos 作为您的服务注册与发现,可以将 spring.cloud.nacos.discovery.enabled 设置为 false。
- 官方参考
-
* 示例: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example
* 详细:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery
3. 示例-客户端配置Nacos注册中心与配置中心
-
pom.xml
```xml <!--注册中心客户端--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--配置中心客户端--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> ```
-
bootstrap.yml
server: port: 7002 spring: application: name: @artifactId@ cloud: nacos: discovery: server-addr: 127.0.0.1:8848 namespace: sms-dev # 设置 nacos client 使用这个 ip 注册到 nacos server , 若不配置则会自动探测。 #ip: 192.160.22.22 config: server-addr: ${spring.cloud.nacos.discovery.server-addr} file-extension: yaml namespace: sms-dev group: DEFAULT_GROUP shared-configs: - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} group: @nacos.group@ refresh: false profiles: active: @profiles.active@
-
注意:版本 2.1.x.RELEASE 对应的是 Spring Boot 2.1.x 版本。版本 2.0.x.RELEASE 对应的是 Spring Boot 2.0.x 版本,版本 1.5.x.RELEASE 对应的是 Spring Boot 1.5.x 版本。
注意: 关于 Nacos 的配置需要在 bootstrap.yaml 中配置。
-
注意: @RefreshScope与数据源之间存在冲突!!
因为项目是多数据源,所以使用的是自定义数据源配置的DataSource,用@Bean注入。
在SpringBoot 2.0以上默认使用Hikari连接池,一旦连接池启动,就无法再修改HikariDataSource,所以刷新配置时连带数据源一起刷新,于是会报错。
Caused by: java.lang.IllegalStateException: The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.
解决方法: 在自定义的DataSource上加入注解@RefreshScope,或者使用spring.scloud.refresh.extra-refreshable配置指定classname列表即可。
查看Hikari的默认配置即可发现,这个与刷新配置之间是存在冲突的。 因此在数据源配置类中加入注释,这样每次刷新配置的时候会重新刷新这个Bean,那么就可以保证不会报错,这样的spring的刷新机制就可以顺利执行下去了。
4. 常见问题
-
SpringCloud 以及NACOS服务注册IP选择问题
-
Nacos 权限配置
Server端打开权限控制开关。修改con/application.properties内容:
nacos.core.auth.enabled=true
这个开关采用了热加载模式,无需重启Server即可生效。因此当权限控制功能使用有异常时,可以直接回滚到不鉴权的模式。