跳到主要内容

配置管理基础

配置管理是 Nacos 的核心功能之一,本章介绍 Nacos 配置管理的核心概念和使用方法。

配置管理概述

在传统应用中,配置通常硬编码在代码中或放在配置文件里。这种方式存在以下问题:

  • 修改配置需要重新部署:每次修改配置都需要重新打包、部署应用,影响发布效率
  • 多环境配置管理困难:开发、测试、生产环境的配置难以统一管理,容易出错
  • 配置变更难以追踪:无法记录配置的变更历史,难以定位问题和回滚
  • 配置分散:多个服务的配置分散在各处,难以集中管理和监控
  • 无法动态调整:运行时无法动态调整配置,需要重启应用才能生效

Nacos 配置中心解决了这些问题,提供了集中化、动态化的配置管理能力。

核心能力

Nacos 配置中心提供以下核心能力:

  • 动态配置:配置修改后实时推送到客户端,无需重启应用即可生效
  • 配置版本管理:记录每次配置变更的历史版本,支持一键回滚
  • 灰度发布:支持配置的灰度推送,可以先在小范围验证再全量发布
  • 多环境隔离:通过命名空间实现不同环境的配置隔离,互不影响
  • 配置监听:客户端可以监听配置变化,实时响应配置更新
  • 配置加密:支持敏感配置的加密存储,保护敏感信息安全

配置模型

数据模型

Nacos 的配置由三元组唯一确定:

Namespace(命名空间)+ Group(分组)+ Data ID(配置集ID)

这种设计类似于 Maven 的 GAV 坐标,可以精确定位一个配置。每个维度的作用如下:

维度作用示例
Namespace隔离不同环境或租户dev(开发)、test(测试)、prod(生产)
Group对配置进行逻辑分类DEFAULT_GROUP、DATABASE_GROUP、MQ_GROUP
Data ID配置的唯一标识user-service.yaml、application.properties
┌─────────────────────────────────────────────────────────────────┐
│ Nacos 配置模型 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Namespace(命名空间) │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │
│ │ │ Group(分组) │ │ │
│ │ │ ┌─────────────────────────────────────────────┐ │ │ │
│ │ │ │ Data ID(配置集ID) │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ key1=value1 │ │ │ │
│ │ │ │ key2=value2 │ │ │ │
│ │ │ │ key3=value3 │ │ │ │
│ │ │ └─────────────────────────────────────────────┘ │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

命名空间(Namespace)

命名空间用于实现多环境、多租户的配置隔离。最常见的使用场景是区分不同环境:

  • dev:开发环境
  • test:测试环境
  • prod:生产环境

分组(Group)

分组用于对配置进行逻辑分类,例如:

  • DEFAULT_GROUP:默认分组
  • DATABASE_GROUP:数据库配置
  • MQ_GROUP:消息队列配置

Data ID

Data ID 是配置集的唯一标识。在 Spring Cloud 中,Data ID 的命名格式为:

${prefix}-${spring.profiles.active}.${file-extension}

例如:user-service-dev.yaml

创建配置

通过控制台创建

  1. 登录 Nacos 控制台
  2. 进入「配置管理」->「配置列表」
  3. 点击「+」创建配置
  4. 填写配置信息:
    • Data ID:配置的唯一标识
    • Group:配置所属分组
    • 配置格式:支持 Properties、YAML、JSON、Text、XML
    • 配置内容:具体的配置内容

通过 API 创建

curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs" \
-d "dataId=user-service.yaml" \
-d "group=DEFAULT_GROUP" \
-d "content=spring:
datasource:
url: jdbc:mysql://localhost:3306/user_db
username: root
password: root"

Spring Cloud 集成

添加依赖

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

配置文件

bootstrap.yml 中配置 Nacos 配置中心:

spring:
application:
name: user-service
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: dev
group: DEFAULT_GROUP
file-extension: yaml

配置加载顺序

Spring Cloud Alibaba Nacos Config 会按以下顺序加载配置,后加载的配置会覆盖先加载的配置:

加载顺序(优先级从低到高):
1. 基础配置:{application}.{file-extension}
2. 环境配置:{application}-{profile}.{file-extension}
3. 共享配置:shared-configs 中配置的共享配置
4. 扩展配置:extension-configs 中配置的扩展配置
5. 本地配置:application.yml/properties(优先级最高)

配置加载原理

配置加载的详细过程:

  1. 应用启动:Spring Boot 应用启动,初始化 ApplicationContext
  2. 加载 bootstrap 配置:读取 bootstrap.yml 中的 Nacos 配置
  3. 连接 Nacos:与 Nacos Server 建立连接
  4. 加载远程配置:按顺序从 Nacos 加载各个配置
  5. 合并配置:将所有配置合并,后者覆盖前者
  6. 刷新上下文:使用合并后的配置刷新 Spring 上下文

配置覆盖规则

当多个配置中存在相同的配置项时,覆盖规则如下:

场景覆盖规则
同一配置的不同版本环境配置覆盖基础配置
不同 Data ID 的配置后加载的覆盖先加载的
远程配置 vs 本地配置本地配置优先级最高(可配置)
共享配置 vs 扩展配置扩展配置覆盖共享配置

可以通过以下方式调整优先级:

spring:
cloud:
config:
override-none: true # 本地配置不覆盖远程配置
allow-override: true # 允许远程配置被覆盖
override-system-properties: false # 系统属性不覆盖远程配置

配置示例

假设有以下配置:

Data ID: user-service.yaml        # 基础配置
Data ID: user-service-dev.yaml # 环境配置
Data ID: common.yaml # 共享配置
spring:
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
# 共享配置
shared-configs:
- data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
# 扩展配置
extension-configs:
- data-id: redis.yaml
group: DATABASE_GROUP
refresh: true

配置热更新

Nacos 支持配置的动态更新,配置修改后无需重启应用即可生效。这是 Nacos 配置中心的核心优势之一。

热更新原理

Nacos 配置热更新的实现原理:

  1. 配置监听:客户端启动时,向 Nacos Server 注册配置监听
  2. 长轮询/gRPC 推送:客户端与 Server 保持长连接,等待配置变更通知
  3. 配置变更:用户在 Nacos 控制台或通过 API 修改配置
  4. 推送通知:Nacos Server 检测到配置变更,向所有监听该配置的客户端推送通知
  5. 客户端更新:客户端收到通知后,拉取最新配置并更新本地缓存
  6. 触发回调:触发用户注册的配置变更回调,更新应用状态

使用 @RefreshScope

在需要动态更新的 Bean 上添加 @RefreshScope 注解。当配置发生变化时,Spring 会重新创建该 Bean,注入最新的配置值。

@RestController
@RefreshScope
public class ConfigController {

@Value("${app.config.title:Default Title}")
private String title;

@Value("${app.config.max-connections:100}")
private Integer maxConnections;

@GetMapping("/config")
public Map<String, Object> getConfig() {
Map<String, Object> result = new HashMap<>();
result.put("title", title);
result.put("maxConnections", maxConnections);
return result;
}
}

@RefreshScope 工作原理

  1. Spring 容器在创建被 @RefreshScope 标注的 Bean 时,会创建一个代理对象
  2. 代理对象持有一个目标 Bean 的引用,目标 Bean 被缓存起来
  3. 当配置变更时,ContextRefresher 会发布 RefreshEvent 事件
  4. 事件处理器收到事件后,清除被 @RefreshScope 标注的 Bean 缓存
  5. 下次访问该 Bean 时,代理对象会重新创建目标 Bean,注入最新配置

使用 @NacosValue

@RestController
public class NacosConfigController {

@NacosValue(value = "${app.config.title}", autoRefreshed = true)
private String title;

@GetMapping("/nacos-config")
public String getTitle() {
return title;
}
}

配置监听

@Component
public class ConfigListener {

@NacosConfigListener(dataId = "user-service.yaml", groupId = "DEFAULT_GROUP")
public void onConfigChange(String newConfig) {
System.out.println("配置发生变化: " + newConfig);
}
}

配置版本管理

Nacos 会记录每次配置变更,支持查看历史版本和回滚。

查看历史版本

  1. 进入「配置管理」->「配置列表」
  2. 点击配置的「历史版本」
  3. 查看所有历史版本

回滚配置

  1. 进入历史版本列表
  2. 选择要回滚的版本
  3. 点击「回滚」

API 操作

# 获取配置历史版本
curl "http://127.0.0.1:8848/nacos/v1/cs/history?dataId=user-service.yaml&group=DEFAULT_GROUP&pageNo=1&pageSize=10"

# 回滚到指定版本
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=user-service.yaml&group=DEFAULT_GROUP&nid=123"

灰度发布

Nacos 支持配置的灰度发布,可以将新配置推送给部分实例进行验证。

通过控制台灰度发布

  1. 进入配置详情页
  2. 点击「灰度发布」
  3. 选择灰度实例(通过 IP 或标签筛选)
  4. 编辑灰度配置
  5. 发布灰度配置

灰度配置示例

# 原配置
app:
feature:
new-feature: false

# 灰度配置(仅对灰度实例生效)
app:
feature:
new-feature: true

多环境管理

使用命名空间隔离环境

# 开发环境配置
spring:
cloud:
nacos:
config:
namespace: dev
group: DEFAULT_GROUP

# 生产环境配置
spring:
cloud:
nacos:
config:
namespace: prod
group: DEFAULT_GROUP

使用 Profile 隔离环境

spring:
profiles:
active: dev
cloud:
nacos:
config:
file-extension: yaml

Nacos 会加载 user-service-dev.yaml 配置文件。

推荐方案

推荐结合命名空间和 Profile 使用:

  • 使用命名空间隔离不同环境(dev/test/prod)
  • 使用 Profile 区分同一环境下的不同配置(如不同的数据库)

配置快照与容灾

配置快照是 Nacos 客户端提供的重要容灾机制,能够在 Nacos Server 不可用时保证应用继续运行。

什么是配置快照

配置快照是 Nacos 客户端 SDK 在本地生成的配置副本。当客户端从 Nacos Server 获取配置后,会将配置保存到本地文件系统中。这个快照类似于 Git 中的本地 commit,也类似于缓存,但与普通缓存不同的是,配置快照没有过期时间的概念。

快照存储位置

配置快照默认存储在用户主目录下的 nacos/config 目录中:

${user.home}/nacos/config/
├── fixed-127.0.0.1_8848-xxx/ # 按服务器地址分组
│ ├── config-data/ # 配置数据目录
│ │ ├── DEFAULT_GROUP/ # 按分组组织
│ │ │ └── user-service.yaml # 具体配置文件
│ └── failover/ # 故障转移目录
└── ...

快照的工作原理

┌─────────────────────────────────────────────────────────────────┐
│ 配置快照工作原理 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 正常情况 │ │
│ │ │ │
│ │ 1. 应用启动 → 从 Nacos Server 获取配置 │ │
│ │ 2. 获取成功 → 保存到本地快照 │ │
│ │ 3. 配置变更 → 更新本地快照 │ │
│ │ │ │
│ │ ┌──────────┐ 获取配置 ┌──────────┐ │ │
│ │ │ 应用客户端 │ ────────────────> │ Nacos │ │ │
│ │ └──────────┘ │ Server │ │ │
│ │ │ └──────────┘ │ │
│ │ │ 保存快照 │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ 本地快照 │ │ │
│ │ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 故障情况 │ │
│ │ │ │
│ │ 1. Nacos Server 不可用 │ │
│ │ 2. 客户端无法连接 │ │
│ │ 3. 自动使用本地快照启动 │ │
│ │ 4. 应用正常运行,等待 Server 恢复 │ │
│ │ │ │
│ │ ┌──────────┐ 连接失败 ┌──────────┐ │ │
│ │ │ 应用客户端 │ ────────────────✕ │ Nacos │ │ │
│ │ └──────────┘ │ Server │ │ │
│ │ │ │ (不可用) │ │ │
│ │ │ 使用快照 │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ 本地快照 │ ──────────────────> 应用正常启动 │ │
│ │ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

快照的生命周期

阶段操作说明
首次获取创建快照客户端首次成功获取配置后,创建本地快照文件
配置更新更新快照服务端配置变更推送后,客户端更新本地快照
服务不可用使用快照Nacos Server 不可用时,客户端使用快照启动
服务恢复同步快照服务恢复后,客户端对比 MD5,更新快照

配置快照相关参数

spring:
cloud:
nacos:
config:
# 快照相关配置
cache-dir: ${user.home}/nacos/config # 快照存储目录
# 是否在启动时优先使用本地快照
# true: 启动时先检查本地快照,存在则直接使用,异步检查更新
# false: 启动时必须连接服务端获取配置
first-sync-from-server: false

故障转移(Failover)

Nacos 还支持故障转移机制,允许在 Nacos Server 长期不可用时,通过手动修改本地快照来更新配置。

故障转移目录${user.home}/nacos/config/{server}/failover/

当故障转移目录中存在配置文件时,客户端会优先使用该目录中的配置,而不是快照目录中的配置。

使用场景

  1. Nacos Server 短期不可用:自动使用快照,无需干预
  2. Nacos Server 长期不可用:运维人员可修改 failover 目录中的配置文件,实现应急配置变更
故障转移流程:
1. 发现 Server 不可用
2. 检查 failover 目录是否有配置
3. 如果有,使用 failover 配置
4. 如果没有,使用快照配置
5. 后台持续尝试连接 Server
6. Server 恢复后,同步最新配置

容灾最佳实践

1. 定期备份快照

虽然 Nacos 客户端会自动维护快照,但建议定期备份快照目录,以防本地文件丢失:

# 备份快照目录
tar -czf nacos-snapshot-$(date +%Y%m%d).tar.gz -C ${HOME}/nacos config

# 恢复快照
tar -xzf nacos-snapshot-20240101.tar.gz -C ${HOME}/nacos

2. 监控快照状态

通过应用的健康检查端点监控快照状态:

@RestController
public class ConfigHealthController {

@Value("${spring.cloud.nacos.config.cache-dir}")
private String cacheDir;

@GetMapping("/config-health")
public Map<String, Object> configHealth() {
Map<String, Object> result = new HashMap<>();

File snapshotDir = new File(cacheDir);
result.put("snapshotDir", cacheDir);
result.put("exists", snapshotDir.exists());
result.put("lastModified", snapshotDir.lastModified());

// 检查关键配置的快照是否存在
String[] criticalConfigs = {"application.yaml", "database.yaml"};
Map<String, Boolean> snapshots = new HashMap<>();
for (String config : criticalConfigs) {
File snapshot = new File(cacheDir + "/" + config);
snapshots.put(config, snapshot.exists());
}
result.put("snapshots", snapshots);

return result;
}
}

3. 应急预案

制定配置中心故障的应急预案:

应急预案步骤:
1. 发现配置中心故障
2. 确认应用是否正常启动(使用快照)
3. 如果需要紧急修改配置:
a. 定位应用的快照目录
b. 在 failover 目录创建/修改配置文件
c. 重启应用或触发配置刷新
4. 联系运维人员恢复 Nacos Server
5. 服务恢复后,验证配置同步

4. 多环境快照隔离

不同环境的应用应该使用不同的快照目录:

# 开发环境
spring:
cloud:
nacos:
config:
cache-dir: ${user.home}/nacos/config-dev

# 生产环境
spring:
cloud:
nacos:
config:
cache-dir: ${user.home}/nacos/config-prod

快照与缓存的区别

特性配置快照普通缓存
过期时间
持久化是(存储在文件系统)通常否(存储在内存)
容灾能力强(Server 不可用时仍可用)
更新机制Server 推送 + MD5 校验定时过期刷新
主要目的容灾性能优化

配置快照不仅提供了性能优化(减少网络请求),更重要的是提供了强大的容灾能力,确保即使配置中心完全不可用,应用也能正常启动和运行。

配置最佳实践

1. 配置分类策略

合理的配置分类可以提高配置的可维护性。建议按以下维度进行分类:

按服务分类

DEFAULT_GROUP
├── user-service.yaml # 用户服务配置
├── order-service.yaml # 订单服务配置
├── payment-service.yaml # 支付服务配置
└── common.yaml # 公共配置

按功能模块分类

DATABASE_GROUP
├── mysql.yaml # MySQL 配置
├── redis.yaml # Redis 配置
└── mongodb.yaml # MongoDB 配置

MQ_GROUP
├── kafka.yaml # Kafka 配置
└── rocketmq.yaml # RocketMQ 配置

CACHE_GROUP
├── local-cache.yaml # 本地缓存配置
└── distributed-cache.yaml # 分布式缓存配置

配置拆分原则

  • 将频繁变动的配置与稳定配置分离
  • 将敏感配置与普通配置分离
  • 将环境相关配置与环境无关配置分离

2. 敏感配置加密

对于敏感配置(如数据库密码、API 密钥等),必须进行加密存储,防止信息泄露。

使用 Jasypt 加密

1. 添加依赖

<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>

2. 配置加密密钥

# 建议通过环境变量传入,不要硬编码
jasypt:
encryptor:
password: ${JASYPT_ENCRYPTOR_PASSWORD}
algorithm: PBEWithMD5AndDES

3. 加密敏感数据

public class ConfigEncryption {
public static void main(String[] args) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("your-secret-key");
encryptor.setAlgorithm("PBEWithMD5AndDES");

// 加密密码
String encrypted = encryptor.encrypt("my-db-password");
System.out.println("加密后: ENC(" + encrypted + ")");

// 解密验证
String decrypted = encryptor.decrypt(encrypted);
System.out.println("解密后: " + decrypted);
}
}

4. 在 Nacos 中使用加密配置

spring:
datasource:
url: jdbc:mysql://localhost:3306/user_db
username: root
# 使用 ENC() 包裹加密值
password: ENC(加密后的密码)

加密最佳实践

  • 密钥管理:加密密钥不要存储在代码库中,应通过环境变量或密钥管理系统传递
  • 定期轮换:定期更换加密密钥和敏感配置值
  • 权限控制:限制敏感配置的访问权限,只有授权人员才能查看和修改
  • 审计日志:记录敏感配置的访问和修改日志

使用 Nacos 内置加密(2.2.0+)

Nacos 2.2.0+ 支持配置内容加密:

服务端配置

# 开启配置加密
nacos.config.encryption.enabled=true
nacos.config.encryption.key=your-encryption-key

客户端配置

spring:
cloud:
nacos:
config:
encryption:
enabled: true
key: your-encryption-key

3. 配置变更通知

配置变更后,通过以下方式通知相关人员:

  • 配置变更审计日志
  • 钉钉/企业微信通知
  • 配置变更审批流程

4. 配置备份

定期备份 Nacos 配置:

# 导出配置
curl "http://127.0.0.1:8848/nacos/v1/cs/configs?export=true&dataId=&group=&tenant=dev" -o config.zip

# 导入配置
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?import=true&tenant=dev" -F "[email protected]"

5. 配置格式规范

推荐使用 YAML 格式,具有更好的可读性:

# 数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/user_db
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver

# Redis 配置
spring:
redis:
host: localhost
port: 6379
password:
database: 0

常见问题

1. 配置加载顺序问题

如果多个配置文件中有相同的配置项,后加载的会覆盖先加载的。可以通过调整配置加载顺序解决:

spring:
cloud:
nacos:
config:
extension-configs:
- data-id: base.yaml
order: 1
- data-id: override.yaml
order: 2

2. 配置不更新

检查以下几点:

  • 是否添加了 @RefreshScope 注解
  • 配置的 refresh 属性是否为 true
  • 检查 Nacos Server 日志是否有推送记录

3. 配置加载失败

检查以下几点:

  • Data ID 和 Group 是否正确
  • 命名空间是否正确
  • 配置格式是否正确
  • 查看应用启动日志

4. 配置内容过长

Nacos 对配置内容有长度限制,如果配置过长,建议:

  • 拆分为多个配置文件
  • 使用配置引用
  • 压缩配置内容

下一步