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,理解基本概念
  • 实践服务注册与发现
  • 掌握配置中心的动态刷新
  • 最后研究集群部署和高可用
相关推荐
yangyanping201082 小时前
广告系统设计二之RTA系统设计
java·spring·mybatis
刘 大 望2 小时前
开发自定义MCP Server并部署
java·spring·ai·语言模型·aigc·信息与通信·ai编程
敖正炀2 小时前
Java 线程状态变化与ObjectMonitor之间的关系
jvm·后端
前端付豪2 小时前
Prompt Playground(实现提示词工作台)
前端·人工智能·后端
无籽西瓜a2 小时前
【西瓜带你学设计模式 | 第三期-工厂方法模式】工厂方法模式——定义、实现方式、优缺点与适用场景以及注意事项
java·后端·设计模式·工厂方法模式
谁在黄金彼岸2 小时前
MariaDB Docker容器权限配置问题分析与解决方案
后端·docker·容器
镜花水月linyi2 小时前
Redis 为什么快?
redis·后端
Walter先生2 小时前
实时行情系统设计:从协议选择到高可用架构,再到数据源选型
后端·架构·实时行情数据源
无籽西瓜a3 小时前
【西瓜带你学设计模式 | 第四期 - 抽象工厂模式】抽象工厂模式 —— 定义、核心结构、实战示例、优缺点与适用场景及模式区别
java·后端·设计模式·软件工程·抽象工厂模式