SpringCloud 服务注册与发现:Nacos 零基础入门实战

🎯 本文适合人群 :SpringCloud 初学者、微服务开发新手

⏱️ 阅读时长 :35 分钟

📌 你将收获:从零搭建 Nacos,实现服务注册与发现,掌握配置中心使用


📖 目录


一、Nacos 快速认识

1.1 Nacos 是什么?

Nacos = Na ming and Co nfiguration Service

中文名:服务注册和配置中心

核心功能

  1. 服务注册与发现:管理微服务实例
  2. 配置管理:集中管理配置文件
  3. 服务健康监测:实时监控服务状态

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:访问控制台

  1. 打开 Nacos 控制台:http://localhost:8848/nacos
  2. 点击【服务管理】→【服务列表】
  3. 看到 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 配置多实例
  1. 右键 UserServiceApplication → Copy Configuration
  2. 修改配置名为 UserService-8082
  3. 添加 VM options:-Dserver.port=8082
  4. 点击【Allow parallel run】
  5. 启动多个实例

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:启动并测试

启动顺序

  1. 启动 Nacos
  2. 启动用户服务(3 个实例:8081、8082、8083)
  3. 启动订单服务(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    │             │
│              │  (数据持久化) │             │
│              └─────────────┘             │
└─────────────────────────────────────────┘

部署步骤

  1. 准备 3 台服务器

    • 192.168.1.101
    • 192.168.1.102
    • 192.168.1.103
  2. 配置 MySQL(创建 nacos_config 数据库)

  3. 修改 conf/cluster.conf

    复制代码
    192.168.1.101:8848
    192.168.1.102:8848
    192.168.1.103:8848
  4. 修改 conf/application.properties

    properties 复制代码
    spring.datasource.platform=mysql
    db.num=1
    db.url.0=jdbc:mysql://192.168.1.100:3306/nacos_config
    db.user=root
    db.password=root123
  5. 启动集群(每台机器):

    bash 复制代码
    sh startup.sh  # 不加 -m standalone
  6. 配置 Nginx 负载均衡

    nginx 复制代码
    upstream 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

步骤

  1. 创建数据库:nacos_config

  2. 导入 SQL:conf/nacos-mysql.sql

  3. 修改配置:conf/application.properties

    properties 复制代码
    spring.datasource.platform=mysql
    db.num=1
    db.url.0=jdbc:mysql://localhost:3306/nacos_config
    db.user=root
    db.password=root123

九、常见问题排查

问题 1:服务注册失败

现象:启动服务后,Nacos 控制台看不到服务

排查步骤

  1. 检查 Nacos 是否启动

    bash 复制代码
    curl http://localhost:8848/nacos
  2. 检查配置是否正确

    yaml 复制代码
    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848  # 地址是否正确?
  3. 查看日志

    复制代码
    Caused by: java.net.ConnectException: Connection refused
    → Nacos 未启动或地址错误
  4. 检查防火墙

    bash 复制代码
    # 开放 8848 端口
    firewall-cmd --add-port=8848/tcp --permanent

问题 2:配置不生效

现象:修改 Nacos 配置后,服务未刷新

排查步骤

  1. 检查 @RefreshScope 注解

    java 复制代码
    @RefreshScope  // 必须添加此注解
    @RestController
    public class ConfigController { ... }
  2. 检查 Data ID 是否正确

    复制代码
    服务名:user-service
    Data ID:user-service.yaml  ← 必须一致
  3. 查看配置监听日志

    复制代码
    [fixed-localhost_8848] [add-listener] ok, tenant=public, dataId=user-service.yaml

问题 3:服务调用失败

现象No instances available for user-service

排查步骤

  1. 检查服务是否注册:Nacos 控制台查看

  2. 检查命名空间和分组:确保一致

  3. 检查 @LoadBalanced 注解

    java 复制代码
    @Bean
    @LoadBalanced  // 必须添加
    public RestTemplate restTemplate() { ... }

十、常见面试题

面试题 1:Nacos 的核心功能有哪些?

参考答案

  1. 服务注册与发现

    • 服务注册:服务启动时自动注册到 Nacos
    • 服务发现:从 Nacos 查询服务实例列表
    • 健康检查:心跳机制检测服务状态
  2. 配置管理

    • 集中管理:所有配置存储在 Nacos
    • 动态刷新:配置修改后自动生效
    • 多环境:dev、test、prod 隔离
    • 版本管理:配置历史版本,支持回滚
  3. 命名空间与分组

    • 命名空间:环境隔离
    • 分组:业务隔离

面试题 2:Nacos 的服务注册流程是什么?

参考答案

  1. 服务启动,读取配置
  2. 构建服务实例信息(IP、端口、权重等)
  3. 发送注册请求到 Nacos Server
  4. Nacos Server 保存实例信息到注册表
  5. 启动心跳任务(每 5 秒发送一次)
  6. Nacos 定时检查心跳:
    • 15 秒未收到 → 标记不健康
    • 30 秒未收到 → 剔除实例

面试题 3:Nacos 的配置动态刷新原理是什么?

参考答案

  1. 长轮询机制

    • 客户端发送配置查询请求到 Nacos
    • Nacos 不立即返回,保持连接(最长 30 秒)
    • 如果配置有变化,立即返回
    • 客户端接收到变化,刷新配置
    • 客户端继续发起下一次长轮询
  2. 配置刷新流程

    复制代码
    ① 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 配置文件的加载优先级是什么?

参考答案

优先级(从高到低)

  1. ${spring.application.name}-${spring.profiles.active}.${file-extension}

    • 示例:user-service-prod.yaml
  2. ${spring.application.name}.${file-extension}

    • 示例:user-service.yaml
  3. 共享配置(shared-configs)

    • 示例:common-config.yaml
  4. 本地配置(application.yml)

规则:相同配置项,高优先级覆盖低优先级


面试题 8:Nacos 的临时实例和持久实例有什么区别?

参考答案

对比项 临时实例 持久实例
心跳 客户端主动上报 Nacos 主动探测
下线 心跳超时自动剔除 手动下线
存储 内存 磁盘(MySQL)
适用场景 微服务(默认) 数据库、MQ

配置方式

yaml 复制代码
spring:
  cloud:
    nacos:
      discovery:
        ephemeral: false  # false = 持久实例

面试题 9:Nacos 如何保证高可用?

参考答案

  1. 集群部署

    • 部署 3 个以上节点
    • 数据同步(Raft 协议)
  2. 数据持久化

    • 使用 MySQL 存储配置和服务信息
    • 主从复制保证数据库高可用
  3. 负载均衡

    • Nginx 做负载均衡
    • 客户端配置多个 Nacos 地址
  4. 健康检查

    • 心跳机制自动剔除故障实例
    • 保护阈值防止雪崩

面试题 10:Nacos 如何实现配置的版本管理和回滚?

参考答案

版本管理

Nacos 自动记录配置的历史版本:

  • 每次发布配置,生成一个新版本
  • 控制台可查看所有历史版本

回滚操作

  1. 进入配置管理 → 配置列表
  2. 点击配置 → 历史版本
  3. 选择要回滚的版本 → 回滚

实现原理

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,理解基本概念
  • 实践服务注册与发现
  • 掌握配置中心的动态刷新
  • 最后研究集群部署和高可用
相关推荐
神奇小汤圆4 小时前
MySQL / MariaDB 主从复制架构实战指南
后端
用户6757049885024 小时前
【AI开发实战】从想法到上线,我用AI全栈开发了一款记账微信小程序
后端·aigc·ai编程
Moment4 小时前
作为前端,如果使用 Langgraph 实现第一个 Agent
前端·javascript·后端
神奇小汤圆4 小时前
高并发接口总被打崩?我用 ArrayBlockingQueue + 底层源码深度剖析搞定流控
后端
木易 士心4 小时前
MyBatis Plus 核心功能与用法
java·后端·mybatis
Victor3564 小时前
MongoDB(93)如何使用变更流跟踪数据变化?
后端
用户6757049885024 小时前
全网都在推 Claude Code,但只有这篇文章教你如何“真正”能用
后端·aigc·claude
Victor3564 小时前
MongoDB(94)什么是MongoDB Atlas?
后端
苏三说技术4 小时前
为什么越来越多的大厂抛弃MCP,转向CLI?
后端
Rust研习社5 小时前
Rust 写时克隆智能指针 Cow
后端·rust·编程语言