🎯 本文适合人群 :SpringCloud 初学者、微服务开发新手
⏱️ 阅读时长 :35 分钟
📌 你将收获:从零搭建 Nacos,实现服务注册与发现,掌握配置中心使用
📖 目录
- [一、Nacos 快速认识](#一、Nacos 快速认识)
- [二、Nacos 安装与启动](#二、Nacos 安装与启动)
- 三、服务注册实战
- 四、服务发现实战
- [五、Nacos 配置中心](#五、Nacos 配置中心)
- 六、命名空间与分组
- [七、Nacos 高级特性](#七、Nacos 高级特性)
- 八、生产环境部署
- 九、常见问题排查
- 十、常见面试题
一、Nacos 快速认识
1.1 Nacos 是什么?
Nacos = Na ming and Co nfiguration Service
中文名:服务注册和配置中心
核心功能:
- 服务注册与发现:管理微服务实例
- 配置管理:集中管理配置文件
- 服务健康监测:实时监控服务状态
1.2 为什么选择 Nacos?
对比其他注册中心:
| 特性 | Nacos | Eureka | Consul | Zookeeper |
|---|---|---|---|---|
| 服务发现 | ✅ | ✅ | ✅ | ✅ |
| 配置管理 | ✅ | ❌ | ✅ | ✅ |
| 健康检查 | TCP/HTTP/MySQL | HTTP | TCP/HTTP/gRPC | TCP |
| 控制台 | 功能丰富 | 基础功能 | 功能丰富 | 无 |
| CAP 模型 | CP + AP | AP | CP | CP |
| 维护状态 | ✅ 活跃 | ❌ 停止维护 | ✅ 活跃 | ✅ 活跃 |
| 学习成本 | 低 | 低 | 中 | 高 |
Nacos 优势:
- ✅ 功能全面(注册 + 配置)
- ✅ 控制台友好
- ✅ 性能优秀
- ✅ 国产开源,社区活跃
- ✅ 阿里云商业支持
1.3 Nacos 架构图
┌─────────────────────────────────────────────────────┐
│ Nacos 架构全景图 │
├─────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────┐ │
│ │ Nacos Server (8848) │ │
│ ├─────────────────────────┤ │
│ │ ① 服务注册表 │ │
│ │ ② 配置存储 │ │
│ │ ③ 健康检查 │ │
│ │ ④ 控制台 │ │
│ └─────────────────────────┘ │
│ ↑ ↓ │
│ 注册/心跳 查询/拉取配置 │
│ │ │ │
│ ┌──────────┼──────────┼──────────┐ │
│ │ │ │ │ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │用户服务│ │订单服务│ │商品服务│ │支付服务│ │
│ │:8081 │ │:8082 │ │:8083 │ │:8084 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
└─────────────────────────────────────────────────────┘
二、Nacos 安装与启动
2.1 环境准备
系统要求:
- JDK 8+(推荐 JDK 11)
- 内存:2GB+
- 磁盘:1GB+
2.2 下载 Nacos
方式 1:官网下载
访问:https://github.com/alibaba/nacos/releases
下载:nacos-server-2.2.3.tar.gz(推荐最新稳定版)
方式 2:命令行下载
bash
# Linux/Mac
wget https://github.com/alibaba/nacos/releases/download/2.2.3/nacos-server-2.2.3.tar.gz
# 解压
tar -zxvf nacos-server-2.2.3.tar.gz
cd nacos
Windows 下载 ZIP 包并解压即可
2.3 启动 Nacos(单机模式)
Linux/Mac 启动
bash
# 进入 bin 目录
cd nacos/bin
# 单机模式启动
sh startup.sh -m standalone
# 查看日志
tail -f ../logs/start.out
Windows 启动
bash
# 进入 bin 目录
cd nacos\bin
# 单机模式启动
startup.cmd -m standalone
# 或双击 startup.cmd,然后修改文件,添加 set MODE="standalone"
启动成功标志:
Nacos started successfully in stand alone mode. use embedded storage
2.4 访问控制台
地址:http://localhost:8848/nacos
默认账号/密码:nacos / nacos
控制台界面:
┌──────────────────────────────────────────┐
│ Nacos 控制台 │
├──────────────────────────────────────────┤
│ 侧边栏: │
│ ├─ 服务管理 │
│ │ ├─ 服务列表(查看已注册的服务) │
│ │ └─ 订阅者列表 │
│ ├─ 配置管理 │
│ │ ├─ 配置列表 │
│ │ └─ 历史版本 │
│ ├─ 命名空间 │
│ └─ 集群管理 │
└──────────────────────────────────────────┘
2.5 Docker 启动(推荐开发环境)
bash
# 拉取镜像
docker pull nacos/nacos-server:v2.2.3
# 单机模式启动
docker run -d \
--name nacos \
-e MODE=standalone \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
nacos/nacos-server:v2.2.3
# 查看日志
docker logs -f nacos
三、服务注册实战
3.1 创建服务提供者(用户服务)
步骤 1:创建 Spring Boot 项目
xml
<!-- pom.xml -->
<dependencies>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<!-- 版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
步骤 2:配置文件
yaml
# application.yml
server:
port: 8081 # 服务端口
spring:
application:
name: user-service # 服务名(重要!注册到 Nacos 的名字)
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos 地址
# username: nacos # Nacos 账号(可选)
# password: nacos # Nacos 密码(可选)
namespace: public # 命名空间(默认 public)
group: DEFAULT_GROUP # 分组(默认 DEFAULT_GROUP)
# 实例配置
ip: 127.0.0.1 # 实例 IP(可选,默认自动获取)
port: ${server.port} # 实例端口
weight: 1 # 权重(1-100,默认 1)
cluster-name: DEFAULT # 集群名称
# 元数据(可选)
metadata:
version: 1.0.0 # 版本号
region: beijing # 地区
# 日志配置(方便查看注册过程)
logging:
level:
com.alibaba.nacos: debug
步骤 3:启动类
java
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* 用户服务启动类
*
* @EnableDiscoveryClient:开启服务发现功能
* - 自动注册服务到 Nacos
* - 自动发现其他服务
*/
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
步骤 4:创建控制器
java
package com.example.userservice.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
/**
* 用户控制器
*/
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 从配置文件读取端口号
* 用于区分不同实例
*/
@Value("${server.port}")
private String port;
/**
* 获取用户信息
*
* @param id 用户 ID
* @return 用户信息
*/
@GetMapping("/{id}")
public String getUserById(@PathVariable Long id) {
// 模拟查询用户
return "用户信息:userId=" + id + ", 来自端口:" + port;
}
/**
* 健康检查接口
*
* @return 状态信息
*/
@GetMapping("/health")
public String health() {
return "用户服务正常,端口:" + port;
}
}
步骤 5:启动服务
bash
# 启动用户服务
mvn spring-boot:run
# 或 IDEA 中直接运行 UserServiceApplication
启动日志:
2024-03-30 10:00:00 INFO Nacos registry, user-service 127.0.0.1:8081 register finished
步骤 6:验证注册
方式 1:访问控制台
- 打开 Nacos 控制台:http://localhost:8848/nacos
- 点击【服务管理】→【服务列表】
- 看到
user-service,说明注册成功 ✅
控制台显示:
服务名 集群数 实例数 健康实例数
user-service 1 1 1
方式 2:API 查询
bash
# 查询服务列表
curl http://localhost:8848/nacos/v1/ns/service/list?pageNo=1&pageSize=10
# 查询具体服务实例
curl http://localhost:8848/nacos/v1/ns/instance/list?serviceName=user-service
3.2 启动多个实例(模拟集群)
方式 1:修改端口启动
bash
# 启动实例 1(端口 8081)
mvn spring-boot:run
# 启动实例 2(端口 8082)
mvn spring-boot:run -Dserver.port=8082
# 启动实例 3(端口 8083)
mvn spring-boot:run -Dserver.port=8083
方式 2:IDEA 配置多实例
- 右键
UserServiceApplication→ Copy Configuration - 修改配置名为
UserService-8082 - 添加 VM options:
-Dserver.port=8082 - 点击【Allow parallel run】
- 启动多个实例
Nacos 控制台查看:
服务名 集群数 实例数 健康实例数
user-service 1 3 3
实例列表:
IP 端口 健康状态 权重
127.0.0.1 8081 健康 ✅ 1
127.0.0.1 8082 健康 ✅ 1
127.0.0.1 8083 健康 ✅ 1
3.3 服务注册原理详解
┌─────────────────────────────────────────────────┐
│ 服务注册流程 │
├─────────────────────────────────────────────────┤
│ │
│ ① 服务启动 │
│ UserServiceApplication.main() │
│ ↓ │
│ ② Spring 容器初始化 │
│ 扫描到 @EnableDiscoveryClient 注解 │
│ ↓ │
│ ③ 自动配置 NacosServiceRegistry │
│ 读取 spring.cloud.nacos.discovery 配置 │
│ ↓ │
│ ④ 构建服务实例信息 │
│ Instance { │
│ serviceName: "user-service", │
│ ip: "127.0.0.1", │
│ port: 8081, │
│ weight: 1, │
│ healthy: true, │
│ metadata: {...} │
│ } │
│ ↓ │
│ ⑤ 发送注册请求到 Nacos │
│ POST /nacos/v1/ns/instance │
│ ↓ │
│ ⑥ Nacos Server 保存实例信息 │
│ 服务注册表.put("user-service", instance) │
│ ↓ │
│ ⑦ 启动心跳任务(每 5 秒发送一次) │
│ ScheduledTask: sendHeartbeat() │
│ ↓ │
│ ⑧ 注册成功 │
│ LOG: Nacos registry finished │
└─────────────────────────────────────────────────┘
心跳机制:
用户服务每 5 秒向 Nacos 发送心跳:
┌──────────┐
│ 用户服务 │ ─────────────────────┐
└──────────┘ │
↓ 心跳(5 秒一次) │
┌──────────────┐ │
│ Nacos Server │ │
│ │ │
│ 15 秒内: │ │
│ ✅ 收到心跳 │ ←────────────────┘
│ → 标记健康 │
│ │
│ 15 秒未收到: │
│ ❌ 无心跳 │
│ → 标记不健康 │
│ │
│ 30 秒未收到: │
│ 🗑️ 剔除实例 │
└──────────────┘
四、服务发现实战
4.1 创建服务消费者(订单服务)
步骤 1:创建项目
xml
<!-- pom.xml -->
<dependencies>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- LoadBalancer(负载均衡) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
步骤 2:配置文件
yaml
# application.yml
server:
port: 8082
spring:
application:
name: order-service # 订单服务名
cloud:
nacos:
discovery:
server-addr: localhost:8848
步骤 3:启动类
java
package com.example.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* 订单服务启动类
*/
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
/**
* 配置 RestTemplate
*
* @LoadBalanced:启用负载均衡
* - 可以使用服务名调用
* - 自动从 Nacos 获取实例列表
* - 自动实现负载均衡
*/
@Bean
@LoadBalanced // 关键注解:启用负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
步骤 4:创建控制器
java
package com.example.orderservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
/**
* 订单控制器
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/**
* 创建订单
*
* 流程:
* 1. 调用用户服务,验证用户是否存在
* 2. 创建订单
*
* @param userId 用户 ID
* @return 订单信息
*/
@PostMapping("/create")
public String createOrder(@RequestParam Long userId) {
// ① 调用用户服务(使用服务名,不需要写 IP 和端口)
// http://user-service 会被解析为具体的实例地址
String url = "http://user-service/user/" + userId;
String userInfo = restTemplate.getForObject(url, String.class);
// ② 验证用户信息
if (userInfo == null) {
return "用户不存在,订单创建失败";
}
// ③ 创建订单(模拟)
String orderId = "ORDER-" + System.currentTimeMillis();
// ④ 返回结果
return "订单创建成功!\n" +
"订单ID:" + orderId + "\n" +
"用户信息:" + userInfo;
}
/**
* 测试负载均衡
*
* 多次调用此接口,观察返回的端口号是否轮询变化
*/
@GetMapping("/test-lb")
public String testLoadBalance() {
// 调用用户服务的健康检查接口
String url = "http://user-service/user/health";
String result = restTemplate.getForObject(url, String.class);
return "负载均衡测试:\n" + result;
}
}
步骤 5:启动并测试
启动顺序:
- 启动 Nacos
- 启动用户服务(3 个实例:8081、8082、8083)
- 启动订单服务(8082)
测试负载均衡:
bash
# 多次调用此接口
curl http://localhost:8082/order/test-lb
# 第 1 次:用户服务正常,端口:8081
# 第 2 次:用户服务正常,端口:8082
# 第 3 次:用户服务正常,端口:8083
# 第 4 次:用户服务正常,端口:8081 ← 轮询
测试创建订单:
bash
# 创建订单
curl -X POST "http://localhost:8082/order/create?userId=1001"
# 返回:
订单创建成功!
订单ID:ORDER-1711769234567
用户信息:用户信息:userId=1001, 来自端口:8081
4.2 服务发现原理详解
┌─────────────────────────────────────────────────┐
│ 服务发现流程 │
├─────────────────────────────────────────────────┤
│ │
│ ① 订单服务调用用户服务 │
│ restTemplate.getForObject( │
│ "http://user-service/user/1001", │
│ String.class │
│ ) │
│ ↓ │
│ ② RestTemplate 拦截请求 │
│ 发现 URL 是服务名(user-service) │
│ ↓ │
│ ③ 从 Nacos 获取服务实例列表 │
│ NacosDiscoveryClient.getInstances( │
│ "user-service" │
│ ) │
│ ↓ │
│ ④ Nacos 返回实例列表 │
│ [ │
│ {ip: "127.0.0.1", port: 8081}, │
│ {ip: "127.0.0.1", port: 8082}, │
│ {ip: "127.0.0.1", port: 8083} │
│ ] │
│ ↓ │
│ ⑤ LoadBalancer 选择一个实例(轮询策略) │
│ 第 1 次选择:127.0.0.1:8081 │
│ ↓ │
│ ⑥ 替换 URL │
│ http://user-service/user/1001 │
│ → │
│ http://127.0.0.1:8081/user/1001 │
│ ↓ │
│ ⑦ 发送 HTTP 请求 │
│ GET http://127.0.0.1:8081/user/1001 │
│ ↓ │
│ ⑧ 接收响应 │
│ "用户信息:userId=1001, 来自端口:8081" │
│ ↓ │
│ ⑨ 返回给调用方 │
└─────────────────────────────────────────────────┘
4.3 使用 DiscoveryClient 获取服务列表
java
package com.example.orderservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 服务发现控制器
*/
@RestController
@RequestMapping("/discovery")
public class DiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
/**
* 获取所有服务名
*
* @return 服务名列表
*/
@GetMapping("/services")
public List<String> getServices() {
return discoveryClient.getServices();
// 返回:["user-service", "order-service"]
}
/**
* 获取指定服务的所有实例
*
* @param serviceName 服务名
* @return 实例列表
*/
@GetMapping("/instances/{serviceName}")
public List<ServiceInstance> getInstances(@PathVariable String serviceName) {
return discoveryClient.getInstances(serviceName);
// 返回:
// [
// {host: "127.0.0.1", port: 8081, serviceId: "user-service"},
// {host: "127.0.0.1", port: 8082, serviceId: "user-service"},
// {host: "127.0.0.1", port: 8083, serviceId: "user-service"}
// ]
}
/**
* 获取服务详细信息
*/
@GetMapping("/detail/{serviceName}")
public String getServiceDetail(@PathVariable String serviceName) {
List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
StringBuilder sb = new StringBuilder();
sb.append("服务名:").append(serviceName).append("\n");
sb.append("实例数:").append(instances.size()).append("\n\n");
for (int i = 0; i < instances.size(); i++) {
ServiceInstance instance = instances.get(i);
sb.append("实例 ").append(i + 1).append(":\n");
sb.append(" 主机:").append(instance.getHost()).append("\n");
sb.append(" 端口:").append(instance.getPort()).append("\n");
sb.append(" URI:").append(instance.getUri()).append("\n");
sb.append(" 元数据:").append(instance.getMetadata()).append("\n\n");
}
return sb.toString();
}
}
五、Nacos 配置中心
5.1 为什么需要配置中心?
传统方式的问题:
问题 1:配置分散
用户服务:application.yml
订单服务:application.yml
商品服务:application.yml
修改数据库地址 → 改 3 个文件 → 重启 3 个服务 ❌
问题 2:环境切换麻烦
dev 环境:application-dev.yml
test 环境:application-test.yml
prod 环境:application-prod.yml
切换环境 → 修改配置 → 打包 → 部署 ❌
问题 3:配置更新需要重启
修改 Redis 地址 → 重启服务 → 影响业务 ❌
使用 Nacos Config:
✅ 集中管理:所有配置存在 Nacos
✅ 动态刷新:修改配置后自动生效,无需重启
✅ 多环境:dev、test、prod 配置隔离
✅ 版本管理:配置历史版本,支持回滚
✅ 权限控制:不同人员不同权限
5.2 配置中心实战
步骤 1:添加依赖
xml
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 配置刷新支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
步骤 2:创建 bootstrap.yml
yaml
# bootstrap.yml(优先级高于 application.yml)
spring:
application:
name: user-service # 服务名
cloud:
nacos:
config:
server-addr: localhost:8848 # Nacos 地址
file-extension: yaml # 配置文件格式(yaml 或 properties)
namespace: public # 命名空间
group: DEFAULT_GROUP # 分组
# 共享配置(多个服务共用)
shared-configs:
- data-id: common-config.yaml # 公共配置
group: DEFAULT_GROUP
refresh: true # 支持动态刷新
步骤 3:在 Nacos 创建配置
登录 Nacos 控制台 → 配置管理 → 配置列表 → 创建配置
配置 1:user-service.yaml(服务专属配置)
yaml
# Data ID: user-service.yaml
# Group: DEFAULT_GROUP
server:
port: 8081
user:
name: 小白
age: 25
email: xiaobai@example.com
配置 2:common-config.yaml(公共配置)
yaml
# Data ID: common-config.yaml
# Group: DEFAULT_GROUP
spring:
datasource:
url: jdbc:mysql://localhost:3306/cloud_db
username: root
password: root123
redis:
host: localhost
port: 6379
步骤 4:读取配置
java
package com.example.userservice.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 配置测试控制器
*
* @RefreshScope:支持配置动态刷新
*/
@RestController
@RequestMapping("/config")
@RefreshScope // 关键注解:支持配置动态刷新
public class ConfigController {
/**
* 从 Nacos 读取配置
*/
@Value("${user.name}")
private String userName;
@Value("${user.age}")
private Integer userAge;
@Value("${user.email}")
private String userEmail;
/**
* 获取配置信息
*/
@GetMapping("/info")
public String getConfig() {
return "配置信息:\n" +
"姓名:" + userName + "\n" +
"年龄:" + userAge + "\n" +
"邮箱:" + userEmail;
}
}
步骤 5:测试动态刷新
① 启动服务
bash
mvn spring-boot:run
② 访问接口
bash
curl http://localhost:8081/config/info
# 返回:
配置信息:
姓名:小白
年龄:25
邮箱:xiaobai@example.com
③ 修改 Nacos 配置
在 Nacos 控制台修改 user-service.yaml:
yaml
user:
name: 老王 # 修改姓名
age: 30 # 修改年龄
email: laowang@example.com
点击【发布】
④ 再次访问(无需重启)
bash
curl http://localhost:8081/config/info
# 返回(配置已自动刷新):
配置信息:
姓名:老王
年龄:30
邮箱:laowang@example.com
5.3 配置文件加载规则
Nacos 配置文件命名规则:
${spring.application.name}-${spring.profiles.active}.${file-extension}
示例:
- user-service.yaml # 默认配置
- user-service-dev.yaml # dev 环境
- user-service-test.yaml # test 环境
- user-service-prod.yaml # prod 环境
优先级(从高到低):
① user-service-prod.yaml # 环境配置
② user-service.yaml # 默认配置
③ common-config.yaml # 共享配置
④ application.yml # 本地配置
5.4 多环境配置
bootstrap.yml:
yaml
spring:
application:
name: user-service
profiles:
active: dev # 当前环境(dev/test/prod)
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yaml
Nacos 创建配置:
user-service-dev.yaml # 开发环境
user-service-test.yaml # 测试环境
user-service-prod.yaml # 生产环境
切换环境:
bash
# 启动时指定环境
java -jar user-service.jar --spring.profiles.active=prod
六、命名空间与分组
6.1 命名空间(Namespace)
作用:环境隔离
┌───────────────────────────────────┐
│ Nacos 命名空间 │
├───────────────────────────────────┤
│ ┌─────────────────────────────┐ │
│ │ dev(开发环境) │ │
│ │ - user-service │ │
│ │ - order-service │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ test(测试环境) │ │
│ │ - user-service │ │
│ │ - order-service │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ prod(生产环境) │ │
│ │ - user-service │ │
│ │ - order-service │ │
│ └─────────────────────────────┘ │
└───────────────────────────────────┘
特点:
✅ 不同命名空间的服务不互通
✅ 配置隔离
创建命名空间:
Nacos 控制台 → 命名空间 → 新建命名空间
命名空间 ID:dev
命名空间名:开发环境
使用命名空间:
yaml
spring:
cloud:
nacos:
discovery:
namespace: dev # 命名空间 ID
config:
namespace: dev
6.2 分组(Group)
作用:业务隔离
同一个命名空间下:
┌────────────────────────────────┐
│ DEFAULT_GROUP(默认分组) │
│ - user-service │
│ - order-service │
└────────────────────────────────┘
┌────────────────────────────────┐
│ PAYMENT_GROUP(支付业务组) │
│ - payment-service │
│ - account-service │
└────────────────────────────────┘
特点:
✅ 同一命名空间下的不同分组可互通
✅ 用于业务模块划分
使用分组:
yaml
spring:
cloud:
nacos:
discovery:
group: PAYMENT_GROUP
config:
group: PAYMENT_GROUP
七、Nacos 高级特性
7.1 权重配置(流量控制)
场景:灰度发布
用户服务 3 个实例:
- 实例 1(8081):权重 90 → 90% 流量
- 实例 2(8082):权重 10 → 10% 流量(新版本)
- 实例 3(8083):权重 0 → 0% 流量(下线)
配置权重:
Nacos 控制台 → 服务管理 → 服务列表 → 详情 → 编辑
权重:10(0-100)
7.2 保护阈值
作用:防止雪崩
场景:用户服务 10 个实例,9 个挂了
不设保护阈值:
只返回 1 个健康实例 → 压力过大 → 崩溃 ❌
设置保护阈值 0.5:
健康实例数 < 50% → 返回所有实例(包括不健康) ✅
让部分请求失败,但不至于全部失败
配置保护阈值:
yaml
spring:
cloud:
nacos:
discovery:
threshold: 0.5 # 保护阈值 50%
7.3 临时实例 vs 持久实例
| 类型 | 说明 | 心跳检测 | 主动探测 | 适用场景 |
|---|---|---|---|---|
| 临时实例 | 主动上报心跳 | ✅ | ❌ | 微服务(默认) |
| 持久实例 | Nacos 主动探测 | ❌ | ✅ | 数据库、MQ |
配置持久实例:
yaml
spring:
cloud:
nacos:
discovery:
ephemeral: false # false = 持久实例
八、生产环境部署
8.1 集群部署
架构图:
┌─────────────────────────────────────────┐
│ Nacos 集群 │
├─────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│
│ │ Nacos 1 │ │ Nacos 2 │ │ Nacos 3 ││
│ │ :8848 │ │ :8848 │ │ :8848 ││
│ └────┬─────┘ └────┬─────┘ └────┬─────┘│
│ │ │ │ │
│ └─────────────┴─────────────┘ │
│ ↓ │
│ ┌─────────────┐ │
│ │ MySQL │ │
│ │ (数据持久化) │ │
│ └─────────────┘ │
└─────────────────────────────────────────┘
部署步骤:
-
准备 3 台服务器:
- 192.168.1.101
- 192.168.1.102
- 192.168.1.103
-
配置 MySQL(创建 nacos_config 数据库)
-
修改 conf/cluster.conf:
192.168.1.101:8848 192.168.1.102:8848 192.168.1.103:8848 -
修改 conf/application.properties:
propertiesspring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://192.168.1.100:3306/nacos_config db.user=root db.password=root123 -
启动集群(每台机器):
bashsh startup.sh # 不加 -m standalone -
配置 Nginx 负载均衡:
nginxupstream nacos-cluster { server 192.168.1.101:8848; server 192.168.1.102:8848; server 192.168.1.103:8848; } server { listen 80; server_name nacos.example.com; location / { proxy_pass http://nacos-cluster; } }
8.2 数据持久化
单机模式:默认使用 Derby 数据库(内嵌,重启数据丢失)
生产环境:使用 MySQL
步骤:
-
创建数据库:
nacos_config -
导入 SQL:
conf/nacos-mysql.sql -
修改配置:
conf/application.propertiespropertiesspring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config db.user=root db.password=root123
九、常见问题排查
问题 1:服务注册失败
现象:启动服务后,Nacos 控制台看不到服务
排查步骤:
-
检查 Nacos 是否启动:
bashcurl http://localhost:8848/nacos -
检查配置是否正确:
yamlspring: cloud: nacos: discovery: server-addr: localhost:8848 # 地址是否正确? -
查看日志:
Caused by: java.net.ConnectException: Connection refused → Nacos 未启动或地址错误 -
检查防火墙:
bash# 开放 8848 端口 firewall-cmd --add-port=8848/tcp --permanent
问题 2:配置不生效
现象:修改 Nacos 配置后,服务未刷新
排查步骤:
-
检查 @RefreshScope 注解:
java@RefreshScope // 必须添加此注解 @RestController public class ConfigController { ... } -
检查 Data ID 是否正确:
服务名:user-service Data ID:user-service.yaml ← 必须一致 -
查看配置监听日志:
[fixed-localhost_8848] [add-listener] ok, tenant=public, dataId=user-service.yaml
问题 3:服务调用失败
现象 :No instances available for user-service
排查步骤:
-
检查服务是否注册:Nacos 控制台查看
-
检查命名空间和分组:确保一致
-
检查 @LoadBalanced 注解 :
java@Bean @LoadBalanced // 必须添加 public RestTemplate restTemplate() { ... }
十、常见面试题
面试题 1:Nacos 的核心功能有哪些?
参考答案:
-
服务注册与发现:
- 服务注册:服务启动时自动注册到 Nacos
- 服务发现:从 Nacos 查询服务实例列表
- 健康检查:心跳机制检测服务状态
-
配置管理:
- 集中管理:所有配置存储在 Nacos
- 动态刷新:配置修改后自动生效
- 多环境:dev、test、prod 隔离
- 版本管理:配置历史版本,支持回滚
-
命名空间与分组:
- 命名空间:环境隔离
- 分组:业务隔离
面试题 2:Nacos 的服务注册流程是什么?
参考答案:
- 服务启动,读取配置
- 构建服务实例信息(IP、端口、权重等)
- 发送注册请求到 Nacos Server
- Nacos Server 保存实例信息到注册表
- 启动心跳任务(每 5 秒发送一次)
- Nacos 定时检查心跳:
- 15 秒未收到 → 标记不健康
- 30 秒未收到 → 剔除实例
面试题 3:Nacos 的配置动态刷新原理是什么?
参考答案:
-
长轮询机制:
- 客户端发送配置查询请求到 Nacos
- Nacos 不立即返回,保持连接(最长 30 秒)
- 如果配置有变化,立即返回
- 客户端接收到变化,刷新配置
- 客户端继续发起下一次长轮询
-
配置刷新流程:
① Nacos 配置修改 ② Nacos 通知客户端 ③ 客户端拉取新配置 ④ 更新 @RefreshScope Bean ⑤ 配置生效
面试题 4:Nacos 和 Eureka 的区别?
参考答案:
| 对比项 | Nacos | Eureka |
|---|---|---|
| 功能 | 注册中心 + 配置中心 | 仅注册中心 |
| CAP | CP + AP | AP |
| 健康检查 | TCP/HTTP/MySQL | HTTP |
| 控制台 | 功能丰富 | 基础功能 |
| 维护状态 | ✅ 活跃 | ❌ 停止维护 |
| 性能 | 更高 | 一般 |
选择建议:新项目使用 Nacos!
面试题 5:Nacos 的 AP 和 CP 模式有什么区别?
参考答案:
CAP 理论:
- C(Consistency):一致性
- A(Availability):可用性
- P(Partition Tolerance):分区容错性
AP 模式(默认):
- 优先保证可用性
- Nacos 集群部分节点挂了,服务仍可用
- 适用场景:临时实例(微服务)
CP 模式:
- 优先保证一致性
- 集群半数以上节点挂了,服务不可用
- 适用场景:持久实例(数据库、MQ)
切换方式:
bash
# 切换到 CP 模式
curl -X PUT 'http://localhost:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
面试题 6:Nacos 如何实现灰度发布?
参考答案:
方案 1:基于权重
新版本实例:权重 10
旧版本实例:权重 90
结果:10% 流量到新版本,90% 到旧版本
方案 2:基于元数据
yaml
# 新版本实例
metadata:
version: v2
# 旧版本实例
metadata:
version: v1
java
// 自定义负载均衡规则
@Bean
public ReactorLoadBalancer<ServiceInstance> versionLoadBalancer() {
// 根据请求头选择版本
String version = request.getHeader("version");
// 过滤匹配版本的实例
}
面试题 7:Nacos 配置文件的加载优先级是什么?
参考答案:
优先级(从高到低):
-
${spring.application.name}-${spring.profiles.active}.${file-extension}- 示例:
user-service-prod.yaml
- 示例:
-
${spring.application.name}.${file-extension}- 示例:
user-service.yaml
- 示例:
-
共享配置(shared-configs)
- 示例:
common-config.yaml
- 示例:
-
本地配置(application.yml)
规则:相同配置项,高优先级覆盖低优先级
面试题 8:Nacos 的临时实例和持久实例有什么区别?
参考答案:
| 对比项 | 临时实例 | 持久实例 |
|---|---|---|
| 心跳 | 客户端主动上报 | Nacos 主动探测 |
| 下线 | 心跳超时自动剔除 | 手动下线 |
| 存储 | 内存 | 磁盘(MySQL) |
| 适用场景 | 微服务(默认) | 数据库、MQ |
配置方式:
yaml
spring:
cloud:
nacos:
discovery:
ephemeral: false # false = 持久实例
面试题 9:Nacos 如何保证高可用?
参考答案:
-
集群部署:
- 部署 3 个以上节点
- 数据同步(Raft 协议)
-
数据持久化:
- 使用 MySQL 存储配置和服务信息
- 主从复制保证数据库高可用
-
负载均衡:
- Nginx 做负载均衡
- 客户端配置多个 Nacos 地址
-
健康检查:
- 心跳机制自动剔除故障实例
- 保护阈值防止雪崩
面试题 10:Nacos 如何实现配置的版本管理和回滚?
参考答案:
版本管理:
Nacos 自动记录配置的历史版本:
- 每次发布配置,生成一个新版本
- 控制台可查看所有历史版本
回滚操作:
- 进入配置管理 → 配置列表
- 点击配置 → 历史版本
- 选择要回滚的版本 → 回滚
实现原理:
sql
-- nacos_config 表记录当前配置
-- nacos_config_history 表记录历史版本
SELECT * FROM nacos_config_history
WHERE data_id = 'user-service.yaml'
ORDER BY id DESC;
总结
本文详细介绍了 Nacos 的核心功能和使用方法:
✅ 服务注册与发现 :自动注册、心跳检测、负载均衡
✅ 配置中心 :集中管理、动态刷新、多环境隔离
✅ 命名空间与分组 :环境隔离、业务隔离
✅ 高级特性 :权重配置、保护阈值、灰度发布
✅ 生产部署:集群部署、数据持久化、高可用
下一篇预告:《SpringCloud 服务调用与负载均衡:OpenFeign 极简使用教程》
📚 学习建议:
- 先单机部署 Nacos,理解基本概念
- 实践服务注册与发现
- 掌握配置中心的动态刷新
- 最后研究集群部署和高可用