跳到主要内容

配置管理

配置管理是微服务架构的核心基础设施。在分布式系统中,统一管理各服务的配置信息至关重要,配置中心应运而生。

为什么需要配置中心

理解配置中心的价值,需要先看看没有配置中心时的困境。

传统配置管理的问题

在传统架构中,配置通常放在应用程序内部,以配置文件的形式存在。修改配置需要重新打包部署应用。这种方式在单体应用中问题不大,但在微服务架构中会变得难以管理。

微服务架构下,服务数量众多,可能有几十甚至上百个服务。每个服务有多套环境:开发、测试、预发布、生产。配置分散在各个服务中,修改时需要逐个服务操作。某些配置需要实时生效,如开关功能、调整阈值,但重新部署耗时太长。配置变更没有历史记录,出了问题难以追溯。

配置中心解决的问题

配置中心将配置从应用中剥离出来,集中管理。它带来以下好处:

统一管理所有服务的配置,一处修改,处处生效。支持多环境隔离,开发、测试、生产配置互不影响。配置变更实时推送,无需重启服务。配置有版本历史,支持回滚。配置变更可审计,追溯问题更容易。

主流配置中心对比

特性Nacos ConfigSpring Cloud ConfigApollo
开发者阿里巴巴Spring 官方携程
配置存储数据库Git 仓库数据库
动态刷新原生支持需配合 Bus原生支持
灰度发布支持不支持支持
配置回滚支持Git 版本控制支持
控制台完善完善
学习成本

对于使用 Nacos 作为服务发现的项目,推荐直接使用 Nacos Config,统一技术栈。对于有严格审计需求的企业级项目,Apollo 是不错的选择。

Nacos 配置管理

Nacos 提供了一体化的服务发现和配置管理能力。使用 Nacos Config 可以实现配置的集中管理、动态更新、灰度发布等功能。

快速开始

添加依赖:

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

配置文件(bootstrap.yml):

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

在 Nacos 控制台创建配置:Data ID 为 user-service-dev.yml,Group 为 DEFAULT_GROUP,内容为服务的配置。

Data ID 命名规则

Nacos 中配置的唯一标识由 Data ID 和 Group 组成。Data ID 通常遵循以下命名规则:

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

prefix 默认为 spring.application.name,也可以通过 spring.cloud.nacos.config.prefix 指定。

spring.profiles.active 是当前环境,如 devtestprod。没有指定 profile 时,Data ID 为 ${prefix}.${file-extension}

file-extension 是配置文件的扩展名,支持 propertiesyamlyml

例如,服务名为 user-service,环境为 dev,扩展名为 yml,则 Data ID 为 user-service-dev.yml

多环境配置

Nacos 通过命名空间实现环境隔离。每个命名空间有唯一的 ID,在配置中指定:

spring:
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: a1b2c3d4-e5f6-7890-abcd-ef1234567890 # 命名空间 ID

在 Nacos 控制台创建命名空间后,会生成一个唯一的 ID。将这个 ID 配置到应用中,应用就会从对应的命名空间获取配置。

不同环境的命名空间 ID 不同,从而实现配置隔离。通过 Spring Profile 可以灵活切换环境:

spring:
profiles:
active: dev
cloud:
nacos:
config:
namespace: ${NACOS_NAMESPACE:dev}

多配置文件加载

微服务通常有公共配置(如数据库、Redis)和私有配置(如服务特定的业务配置)。Nacos 支持加载多个配置文件。

共享配置:

spring:
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yml
shared-configs:
- data-id: common.yml
group: DEFAULT_GROUP
refresh: true
- data-id: database.yml
group: COMMON_GROUP
refresh: true

扩展配置:

spring:
cloud:
nacos:
config:
extension-configs:
- data-id: redis.yml
group: COMMON_GROUP
refresh: true
- data-id: rabbitmq.yml
group: COMMON_GROUP
refresh: true

配置加载优先级从高到低:

  1. 主配置:${prefix}-${profile}.${file-extension}
  2. 扩展配置:extension-configs 列表按顺序,后加载的优先级更高
  3. 共享配置:shared-configs 列表按顺序

refresh 控制配置变更时是否自动刷新。如果配置项有 @RefreshScope 注解,设置为 true 可以实现动态刷新。

配置动态刷新

Nacos Config 支持配置的动态刷新。当配置在 Nacos 控制台修改后,应用可以自动获取最新配置。

使用 @RefreshScope 注解:

@RestController
@RefreshScope
public class ConfigController {

@Value("${app.config.message:default}")
private String message;

@Value("${app.config.timeout:3000}")
private int timeout;

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

当在 Nacos 控制台修改 app.config.messageapp.config.timeout 后,应用会自动更新这些值。

也可以使用 @NacosValue 注解实现更细粒度的刷新:

@RestController
public class ConfigController {

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

@GetMapping("/config")
public String getMessage() {
return message;
}
}

配置监听

可以监听特定配置的变化,在配置变更时执行自定义逻辑:

@Component
public class ConfigChangeListener {

@NacosConfigListener(dataId = "user-service.yml", groupId = "DEFAULT_GROUP")
public void onConfigChange(String newConfig) {
log.info("配置发生变化: {}", newConfig);
// 执行自定义逻辑,如重新初始化连接池
}
}

对于更复杂的场景,可以实现 ApplicationListener 监听配置变更事件:

@Component
public class NacosConfigRefreshListener implements ApplicationListener<NacosConfigReceivedEvent> {

@Override
public void onApplicationEvent(NacosConfigReceivedEvent event) {
log.info("收到配置变更: dataId={}, groupId={}",
event.getDataId(), event.getGroupId());

// 解析配置并执行相应操作
String config = event.getContent();
// ...
}
}

配置加密

敏感配置(如数据库密码、API 密钥)应该加密存储。Nacos 本身不提供加密功能,但可以通过 Jasypt 等工具实现。

添加 Jasypt 依赖:

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

配置加密密钥(建议通过环境变量传入):

jasypt:
encryptor:
password: ${JASYPT_PASSWORD:default}

加密配置值:

spring:
datasource:
password: ENC(加密后的密码)

生成加密密码:

@Test
public void encryptPassword() {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("your-secret-key");
String encrypted = encryptor.encrypt("your-db-password");
System.out.println(encrypted);
}

灰度发布

Nacos 支持配置的灰度发布,可以将新配置先推送到部分实例,验证无问题后再全量发布。

灰度发布通过配置的 Beta 发布功能实现:

  1. 在 Nacos 控制台编辑配置
  2. 点击"发布 Beta"按钮
  3. 指定灰度 IP 列表
  4. 发布后,只有指定 IP 的实例会收到新配置
  5. 验证无问题后,点击"停止 Beta"并全量发布

配置回滚

Nacos 会保留配置的历史版本。当配置修改导致问题时,可以快速回滚:

  1. 在 Nacos 控制台打开配置详情
  2. 切换到"历史版本"标签
  3. 选择要回滚的版本
  4. 点击"回滚"按钮

回滚操作会生成新的历史记录,可以追溯。

Spring Cloud Config

Spring Cloud Config 是 Spring 官方的配置中心,基于 Git 仓库存储配置文件。适合对配置版本控制有强需求的场景。

架构组成

Spring Cloud Config 分为两个部分:Config Server 是配置服务端,从 Git 仓库读取配置;Config Client 是配置客户端,从 Config Server 获取配置。

搭建 Config Server

添加依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>

配置文件:

server:
port: 8888

spring:
cloud:
config:
server:
git:
uri: https://github.com/your-org/config-repo
default-label: main
search-paths: '{application}'
username: your-username
password: your-password

启动类:

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}

配置文件命名规则

Config Server 支持多种 URL 格式访问配置:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml

在 Git 仓库中,配置文件命名如下:

config-repo/
├── user-service.yml # 默认配置
├── user-service-dev.yml # 开发环境配置
├── user-service-test.yml # 测试环境配置
├── user-service-prod.yml # 生产环境配置
└── application.yml # 所有服务共享配置

Config Client 配置

Spring Boot 2.4+ 后,推荐使用 spring.config.import 配置:

spring:
application:
name: user-service
profiles:
active: dev
config:
import: optional:configserver:http://localhost:8888

如果仍想使用 bootstrap.yml,需要添加依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

动态刷新

Spring Cloud Config 默认不自动刷新配置。需要配合 Spring Cloud Bus 或手动触发。

手动刷新:

management:
endpoints:
web:
exposure:
include: refresh

在需要刷新的类上添加 @RefreshScope 注解。修改 Git 仓库中的配置后,调用刷新接口:

curl -X POST http://localhost:8080/actuator/refresh

使用 Spring Cloud Bus 可以实现自动刷新,配置变更时自动推送到所有服务实例。

最佳实践

配置分类管理

合理规划配置的结构:

配置中心
├── 公共配置
│ ├── common.yml # 全局公共配置
│ ├── database.yml # 数据库配置
│ └── redis.yml # Redis 配置
├── 服务配置
│ ├── user-service.yml # 用户服务配置
│ └── order-service.yml # 订单服务配置
└── 环境配置
├── user-service-dev.yml
├── user-service-test.yml
└── user-service-prod.yml

敏感配置加密

所有敏感配置必须加密存储。使用 Jasypt 或类似的加密工具,加密密钥通过环境变量传入,不要硬编码。

配置变更流程

建立规范的配置变更流程:

  1. 在测试环境验证配置变更
  2. 记录变更原因和影响范围
  3. 生产环境先灰度发布
  4. 观察无异常后全量发布
  5. 出问题及时回滚

配置版本管理

即使使用 Nacos,也建议对配置进行版本管理。可以在配置变更时同步到 Git 仓库,保留变更历史。

配置审计

记录配置的变更历史,包括变更人、变更时间、变更内容。Nacos 控制台提供基础的审计功能,也可以集成企业内部的审计系统。

配置热更新注意事项

不是所有配置都适合热更新。数据库连接池参数修改后通常需要重建连接池,缓存配置修改后可能需要清空缓存,线程池参数修改可能需要重启应用。

对于这类配置,建议在修改后重启应用生效,或者在代码中处理配置变更的副作用。

小结

本章详细介绍了配置管理:

配置中心解决了微服务配置分散、难以管理的问题。Nacos Config 是推荐的配置中心,支持动态刷新、灰度发布、配置回滚。Spring Cloud Config 基于 Git 存储配置,适合对版本控制有强需求的场景。敏感配置必须加密存储,建立规范的配置变更流程。