目录
[Nacos 基本介绍](#Nacos 基本介绍)
[Nacos 安装](#Nacos 安装)
[Nacos 快速上手](#Nacos 快速上手)
[配置 Nacos 地址](#配置 Nacos 地址)
[Nacos 负载均衡](#Nacos 负载均衡)
[Nacos 服务实例类型](#Nacos 服务实例类型)
[Nacos 环境隔离](#Nacos 环境隔离)
[Nacos 配置中心](#Nacos 配置中心)
[Data Id](#Data Id)
Nacos 基本介绍
Nacos (Naming and Configuration Service )是阿里巴巴 开源的一个动态服务发现、配置管理和服务管理平台,主要用于构建云原生应用的微服务架构。它提供了一套简单易用的 API 和控制台,帮助开发者实现服务注册与发现、动态配置管理、服务元数据管理以及服务健康监控等功能
目前,Nacos 几乎支持了所有的主流语言,如 Java、C++、Go、Nodejs、Python 等
Nacos 官网:https://nacos.io/
接下来,我们就来安装并使用 Nacos
Nacos 安装
可以直接从官网下载(Nacos Server 下载 | Nacos 官网)或 GitHub(Releases · alibaba/nacos)
将压缩包解压到非中文目录下,进入 bin 目录:

其中:
startup.cmd:windows 平台启动脚本
startup.sh:linux 平台启动脚本
shutdown.cmd:windows 平台停止脚本
shutdown.sh:linux 平台停止脚本
Nacos 默认启动方式为集群 ,在学习阶段使用 单机 即可,因此我们修改配置为单机模式:
打开startup.cmd 修改启动模式:

将其修改为 standalone:

修改后双击startup.cmd 启动:

访问 Nacos 主页:http://127.0.0.1:8848/nacos

Nacos 启动成功
Nacos 启动后,bin 目录下会生成logs 文件夹 ,存放Nacos 相关日志,若启动过程中出现问题,可查看日志进行分析和定位问题
Nacos 快速上手
引入依赖
在父工程的 pom 文件 中引入Spring Cloud Alibaba依赖:
XML
<properties>
<spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<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>
在引入依赖时,需要注意版本之间的对应关系 (版本发布说明-阿里云Spring Cloud Alibaba官网)
在order-service 和 product-service 中引入Nacos 依赖 和Load Balance依赖:
XML
<dependency> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
配置 Nacos 地址
在application.yml 中配置Nacos 地址:
java
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
远程调用
修改 OrderService 远程调用代码,将IP 和端口号 修改为 项目名称:
java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public OrderInfo findOrderInfoById(Integer orderId) {
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
String url = "http://product-service/product/" + orderInfo.getProductId();
ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
}
为 restTemplate 添加**@LoadBalanced**注解:
java
@Configuration
public class BeanConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
启动服务
启动order-service 和product-service ,观察nacos 管理界面:

测试接口 127.0.0.1:8080/order/1:

测试负载均衡
启动多个product-service:

观察 Nacos 控制台:

多次访问接口,观察日志,测试负载均衡:



更多的时候,我们需要对服务流量进行更精细的控制,而 Nacos支持多种负载均衡策略,如权重、同机房、同地域、同环境等
接下来,我们就来具体看一下 Nacos 的具体负载均衡策略
Nacos 负载均衡
服务下线
当某个节点上接口的性能较差时,我们可以第一时间对该节点进行下线


点击下线后,该实例则没有请求再进来了:

上线后,该节点继续接收到请求:

除了对节点进行上下线操作,我们还可以配置这个节点的流量权重
权重配置
编辑对应节点,修改权重值:

节点的默认权重为1,此时将其修改为 0.2
然而,此时多次访问接口,观察日志,我们会发现 9090 端口实例接收的请求并没有变少
这是由于Spring Cloud LoadBalance 组件自身有负载均衡配置方式,因此不支持 Nacos 的权重属性配置,我们需要开启 Nacos 的负载均衡策略,让权重配置生效:
java
spring:
cloud:
loadbalancer:
nacos:
enabled: true
此时再次启动服务,多次访问接口,就会发现 9090 端口实例接收的请求明显比另外两个实例少
同集群优先访问
Nacos 将同一个机房内的实例 ,划分为一个集群 ,因此同集群优先访问 ,在一定程度上也可以理解为同机房优先访问
在微服务架构中,一个服务通常由多个实例共同提供服务,这些实例可以部署在不同的机器上,而这些机器可能会分布在不同机房:

因此,微服务访问时,应尽量访问同机房的实例,当本机房内实例不可用时,才访问其他机房实例:

我们为 product-service 实例配置集群名称:
java
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
cluster-name: BJ # 北京集群
重启 9090 实例,观察 Nacos 控制台,BJ 集群下多了一个实例:

在 VM Option 中设置 9091端口号实例集群为 BJ:
-Dspring.cloud.nacos.discovery.cluster-name=BJ

同样为 9092 端口号实例设置集群为 CD:
-Dspring.cloud.nacos.discovery.cluster-name=CD
重启,观察 Naos 集群实例:

为 order-service 配置集群名称为 BJ:
java
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
cluster-name: BJ # 北京集群
loadbalancer:
nacos:
enabled: true
多次访问接口,观察日志,发现只有 9090 和 9091 端口实例接收到了请求(同集群)
将 9090 端口实例 和 9091 端口实例都下线,再次访问接口,此时 9092 端口实例接收到了请求
健康检查
Nacos 作为注册中心,需要感知服务的健康状态,才能为服务调用方提供良好的服务
Nacos 中提供了两种健康检查机制:
客户端主动上报机制:
服务实例(客户端)每隔 5 秒 向 Nacos Server 发送一次 心跳(Beat)
Nacos Server 收到心跳后,会更新该实例的 最后心跳时间(lastBeat)
如果 15 秒内未收到心跳 ,Server 会将实例标记为 不健康(unhealthy)
如果 30 秒内仍未收到心跳 ,Server 会将实例 自动剔除(注销)

服务器反向探测机制:
Nacos Server 主动发起探测
周期性检查目标实例的端口或健康接口是否可达
若探测失败,标记为不健康

在 Nacos 中,健康检查机制不能主动设置,而是跟 Nacos 的 服务实例类型强相关
Nacos 服务实例类型
Nacos 的服务实例(注册的节点)分为 临时实例 和 非临时实例
临时实例: 生命周期短暂 ,依赖客户端主动上报心跳 维持存活,若客户端停止发送心跳(如进程崩溃、网络中断),Nacos Server 会在一定时间后自动将其实例注销(从服务列表中移除)
非临时实例: 生命周期持久 ,不会因心跳中断而自动下线 ,即使服务宕机,实例仍会保留在 Nacos 服务列表中,需手动删除或通过服务端主动探测判定健康状态
Nacos 中,临时实例 采取客户端上报机制 ,非临时实例 采取服务器反向探测机制

、
观察 Nacos 控制台 ,可以看到默认实例类型 为临时实例:

我们将order-service实例配置为永久实例:
java
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置为非临时实例
重启 order-service 服务:

重启失败,因为 order-service 为临时服务,无法注册持久化实例
Nacos 会记录每个服务实例的 IP 和 端口号,当发现IP 和 端口号都没有发生变化时,Nacos 不允许一个服务实例类型发生变化(临时实例 -> 非临时实例,或 非临时实例 -> 临时实例)
要解决这个问题,我们需要停掉 Nacos 并删除 Nacos 目录下的 \data\protocol\raft 信息,其中保存了应用实例的元数据信息
此时再重启 order-service,观察 Nacos 控制台:

order-service为非临时实例
Nacos 环境隔离
一个服务通常会分为开发环境、测试环境 和 生产环境:
开发环境:开发人员用于开发的服务器,是最基础的环境,一般日志级别设置较低,可能会开启一些调试信息
测试环境:测试人员用来进行测试的服务器,是开发环境到生产环境的过渡环境
生产环境:正式提供对外服务的环境,通常会关闭调试信息
通常情况下,这几个环境是不能互相通信的,Nacos 提供了namespace(命名空间) 来实现环境的隔离,不同的 namespace 服务不可见
默认情况下,所有的服务都在一个namespace(public) 中:

在命名空间中,可以对 namespace 进行操作:

新增命名空间:


配置 namespace ,修改 order-service 命名空间:
java
spring:
cloud:
nacos:
discovery:
namespace: 02153306-6b02-40eb-9027-4916554cb411 # 命名空间ID
重启服务,观察 Nacos 控制台:

此时再访问接口,进行远程调用测试:


product-service 实例不可用
我们将 product-service的其中一个实例命名空间修改为 test:
java
spring:
cloud:
nacos:
discovery:
namespace: 02153306-6b02-40eb-9027-4916554cb411 # 命名空间ID

再次访问,远程调用成功:

Nacos 配置中心
除了注册中心和负载均衡外,Nacos 还是一个配置中心,具有配置管理的功能
若项目的配置都在代码中,就会存在以下问题:
配置文件修改后,服务需要重新部署,微服务架构中,一个服务可能有成百个实例,挨个部署会比较麻烦,且容易出错
多人开发时,配置文件可能经常需要修改,使用同一个配置文件容易出错
配置中心就是对这些配置项进行统一管理,通过配置中心,可以集中查看、修改和删除配置,无需再逐个修改配置文件,提高效率的同时,也降低了出错的风险

服务启动时,从配置中心读取配置项内容,进行初始化
配置项修改时,通知微服务,实现配置的更新加载
在 Nacos 控制台添加配置项:

新增配置项:

Data ID 设置为项目名称,配置格式 为配置内容的数据格式,再设置配置内容
引入 Nacos Config 依赖:
XML
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud 2020.*之后版本需要引⼊bootstrap-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
配置bootstarp.properties (或 bootstarp.yml):
微服务启动前,需要先获取nacos 中的配置 ,并与 application.yml 配置合并 ,在微服务运行之前,Nacos 要求使用 bootstarp.properties(或bootstarp.yml ) 配置文件来配置 Nacos Server 地址**:**
java
spring:
application:
name: product-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
其中,spring.application.name 需要和 nacos 配置管理的 Data ID( 也就是项目名称**)**一致
spring.cloud.nacos.config.server-addr 为 Nacos Server 的地址
配置中心和注册中心的配置是隔离的:
Nacos 配置中心:spring.cloud.nacos.config.server-addr
Nacos 注册中心:spring.cloud.nacos.discovery.server-addr
获取配置:
java
@RequestMapping("/config")
@RefreshScope
@RestController
public class NacosController {
@Value("${nacos.test.num}")
private Integer nacosNum;
@RequestMapping("/get")
public Integer get() {
return this.nacosNum;
}
}
@Value:读取配置
@RefreshScope:配置进行热更新
启动product-service 9090 ,访问接口 127.0.0.1:9090/config/get:

在Nacos 控制台 修改nacos.test.num:

再次访问接口:

Nacos配置管理的命名空间 和服务列表的命名空间 是分别设置的,默认为 public
服务列表的命名空间设置:

而 Nacos 配置管理的命名空间 可在bootstarp.properties中设置:

配置管理设置命名空间后,项目启动时,会从该命名空间下找对应配置项:

访问接口 127.0.0.1:9090/config/get:

Data Id
在Nacos Spring Cloud 中,dataId 的完整格式为:
{prefix}-{spring.profiles.active}.{file-extension}** **{prefix}: 默认为spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix 来配置
{spring.profiles.active}:当前环境对应的 profile** ,若 **spring.profiles.active** 为空,对应 dataId 拼接为 **{prefix}.${file-extension}
${file-extension}: 为配置内容的数据格式 ,可通过配置项spring.cloud.nacos.config.file-extension 来配置
微服务启动时,会从 Nacos 中读取多个配置文件:
{prefix}-{spring.profiles.active}.${file-extension} ,如product-service-dev.properties
{prefix}.{file-extension} ,如 product-service.properties
${prefix} ,如product-service
spring.application.name 、spring.profiles.active 等通过配置文件指定时,必须放在 bootstrap.properties(或bootstrap.yml ) 文件中
在bootstrap.yml 中添加spring.profiles.active 值:
java
spring:
profiles:
active: dev
启动服务,观察日志:

三个文件的优先级为:product-service-dev.properties > product-service.properties > product-service
我们来测试一下:
添加配置:

访问接口 127.0.0.1:9090/config/get:

此时服务获取到了 product-service-dev.properties的值
删除 product-service-dev.properties 配置,再次访问接口:

此时服务获取到了 product-service.properties的值
删除 product-service.properties 配置,再次访问接口:

此时服务获取到了 product-service的值