配置管理
配置管理是微服务架构的核心基础设施。在分布式系统中,统一管理各服务的配置信息至关重要,配置中心应运而生。
为什么需要配置中心
理解配置中心的价值,需要先看看没有配置中心时的困境。
传统配置管理的问题
在传统架构中,配置通常放在应用程序内部,以配置文件的形式存在。修改配置需要重新打包部署应用。这种方式在单体应用中问题不大,但在微服务架构中会变得难以管理。
微服务架构下,服务数量众多,可能有几十甚至上百个服务。每个服务有多套环境:开发、测试、预发布、生产。配置分散在各个服务中,修改时需要逐个服务操作。某些配置需要实时生效,如开关功能、调整阈值,但重新部署耗时太长。配置变更没有历史记录,出了问题难以追溯。
配置中心解决的问题
配置中心将配置从应用中剥离出来,集中管理。它带来以下好处:
统一管理所有服务的配置,一处修改,处处生效。支持多环境隔离,开发、测试、生产配置互不影响。配置变更实时推送,无需重启服务。配置有版本历史,支持回滚。配置变更可审计,追溯问题更容易。
主流配置中心对比
| 特性 | Nacos Config | Spring Cloud Config | Apollo |
|---|---|---|---|
| 开发者 | 阿里巴巴 | 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
配置加载优先级从高到低:
- 主配置:
${prefix}-${profile}.${file-extension} - 扩展配置:
extension-configs列表按顺序,后加载的优先级更高 - 共享配置:
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 发布功能实现:
- 在 Nacos 控制台编辑配置
- 点击"发布 Beta"按钮
- 指定灰度 IP 列表
- 发布后,只有指定 IP 的实例会收到新配置
- 验证无问题后,点击"停止 Beta"并全量发布
配置回滚
Nacos 会保留配置的历史版本。当配置修改导致问题时,可以快速回滚:
- 在 Nacos 控制台打开配置详情
- 切换到"历史版本"标签
- 选择要回滚的版本
- 点击"回滚"按钮
回滚操作会生成新的历史记录,可以追溯。
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 或类似的加密工具,加密密钥通过环境变量传入,不要硬编码。
配置变更流程
建立规范的配置变更流程:
- 在测试环境验证配置变更
- 记录变更原因和影响范围
- 生产环境先灰度发布
- 观察无异常后全量发布
- 出问题及时回滚
配置版本管理
即使使用 Nacos,也建议对配置进行版本管理。可以在配置变更时同步到 Git 仓库,保留变更历史。
配置审计
记录配置的变更历史,包括变更人、变更时间、变更内容。Nacos 控制台提供基础的审计功能,也可以集成企业内部的审计系统。
配置热更新注意事项
不是所有配置都适合热更新。数据库连接池参数修改后通常需要重建连接池,缓存配置修改后可能需要清空缓存,线程池参数修改可能需要重启应用。
对于这类配置,建议在修改后重启应用生效,或者在代码中处理配置变更的副作用。
小结
本章详细介绍了配置管理:
配置中心解决了微服务配置分散、难以管理的问题。Nacos Config 是推荐的配置中心,支持动态刷新、灰度发布、配置回滚。Spring Cloud Config 基于 Git 存储配置,适合对版本控制有强需求的场景。敏感配置必须加密存储,建立规范的配置变更流程。