跳到主要内容

配置管理

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

为什么需要配置中心​

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

传统配置管理的问题​

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

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

配置中心解决的问题​

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

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

主流配置中心对比​

特性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 是当前环境,如 dev、test、prod。没有指定 profile 时,Data ID 为 ${prefix}.${file-extension}。

file-extension 是配置文件的扩展名,支持 properties、yaml、yml。

例如,服务名为 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.message 或 app.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 存储配置,适合对版本控制有强需求的场景。敏感配置必须加密存储,建立规范的配置变更流程。