如何设计一个配置中心?

2025年 阅读约 15 分钟 面试指南 · 系统设计

深入解析配置中心设计:配置存储(Git/DB)、配置热更新(长轮询/WebSocket/Spring Cloud Bus)、灰度发布、版本回滚、Apollo/Nacos架构分析,附面试模拟问答。

一句话总结

配置中心核心功能:配置管理(集中存储、环境隔离、版本管理)、配置热更新(长轮询/WebSocket推送,不重启生效)、灰度发布(按实例/IP/比例逐步推送)、权限审计(谁改了、改了什么)。主流方案:Apollo(携程,功能全面)、Nacos(阿里,配置+注册二合一)、Spring Cloud Config(简单,需配合Bus)。热更新原理:客户端长轮询 → 服务端比较版本号 → 有变化推送新配置 → 客户端刷新Bean。

初级理解

为什么需要配置中心?

# 传统配置文件的问题 # 1. 分散:每个服务有自己的 application.yml # 2. 修改需重启:改配置 → 重新打包 → 重启服务 # 3. 环境管理混乱:dev/test/prod 配置散落各处 # 4. 安全风险:敏感信息(密码)明文在配置文件中 # 配置中心的价值 # 1. 集中管理:所有配置在一个平台 # 2. 热更新:修改配置实时生效,无需重启 # 3. 环境隔离:dev/test/prod 配置分离 # 4. 版本管理:配置变更历史可追溯 # 5. 权限控制:谁可以改什么配置 # 6. 灰度发布:配置逐步生效,降低风险

主流方案对比

方案存储热更新特点
ApolloMySQL长轮询(1s)功能全面,携程开源
NacosMySQL/Derby长轮询配置+注册二合一
Spring Cloud ConfigGit/SVN需配合Bus简单,Spring生态
一句话总结:配置中心解决配置分散、需重启、难管理的问题,Apollo/Nacos是主流。

中级深入

配置热更新原理

# 热更新流程 # 1. 客户端启动 → 从配置中心拉取配置 # 2. 客户端启动长轮询(hold 60s) # 3. 配置变更 → 服务端返回新配置 # 4. 客户端收到新配置 → 刷新本地缓存 # 5. 通知 Spring 环境更新(EnvironmentChangeEvent) # 6. @RefreshScope 的 Bean 重新初始化 # 长轮询 vs WebSocket # 长轮询:客户端发请求,服务端hold住,有变化或超时返回 # 优点:兼容性好(HTTP),防火墙友好 # 缺点:半双工,每次需要重新建立请求 # WebSocket:全双工长连接 # 优点:实时性高,双向通信 # 缺点:需要维护连接,资源消耗大 # Apollo 选择长轮询(1秒间隔) # 配置变更频率低,长轮询足够

配置存储设计

# Apollo 配置存储(MySQL) CREATE TABLE app ( id INT PRIMARY KEY, name VARCHAR(50) # 应用名 ); CREATE TABLE namespace ( id INT PRIMARY KEY, app_id INT, name VARCHAR(50) # namespace名(application/datasource等) ); CREATE TABLE item ( id INT PRIMARY KEY, namespace_id INT, key VARCHAR(128), value TEXT, comment VARCHAR(256) ); CREATE TABLE release ( id INT PRIMARY KEY, namespace_id INT, name VARCHAR(64), # 版本号 configurations TEXT, # 本次发布的配置JSON comment VARCHAR(256), created_at DATETIME );
中级要点:热更新用长轮询(兼容性好);配置存储用MySQL+版本管理。

高级拓展

灰度发布

# 灰度发布策略 # 1. 按实例:指定某些实例先更新 # 2. 按 IP:指定 IP 段先更新 # 3. 按比例:10% → 50% → 100% # Apollo 灰度发布 # 1. 创建灰度版本 # 2. 配置灰度规则(实例/IP) # 3. 灰度实例拉取到新配置 # 4. 观察无问题 → 全量发布 # 5. 有问题 → 回滚 # 灰度实现原理 # 客户端请求带实例信息(IP、hostname) # 服务端根据灰度规则判断是否返回新配置 # 匹配灰度规则 → 返回新配置 # 不匹配 → 返回旧配置

高可用设计

# 配置中心高可用 # 1. 服务端集群:多实例部署,无状态 # 2. DB 高可用:MySQL 主从 + 故障转移 # 3. 客户端缓存:本地文件缓存配置 # 4. 降级策略:配置中心挂了,使用本地缓存 # 客户端缓存策略 # 1. 启动时从配置中心拉取 → 存本地文件 # 2. 配置中心不可用 → 使用本地文件 # 3. 本地文件也没有 → 使用 classpath 默认配置 # Apollo 客户端降级 # 1. 先从内存缓存读 # 2. 内存没有 → 从本地文件读 # 3. 本地文件没有 → 从配置中心拉取 # 4. 配置中心挂了 → 使用上次缓存的配置

实战场景

场景:使用 Apollo 管理配置

# Apollo 配置使用 # application.yml app: id: my-app apollo: meta: http://apollo-config:8080 bootstrap: enabled: true namespaces: application, datasource # 代码中使用 @Value("${timeout:3000}") private int timeout; # 热更新(需要 @RefreshScope) @RestController @RefreshScope public class ConfigController { @Value("${timeout:3000}") private int timeout; @GetMapping("/timeout") public int getTimeout() { return timeout; # 修改配置后实时生效 } }

面试模拟

面试官:配置中心怎么实现热更新?

你:客户端长轮询(hold 60s),服务端比较版本号,有变化返回新配置。客户端收到后刷新本地缓存,发布EnvironmentChangeEvent,@RefreshScope的Bean重新初始化。Apollo用长轮询(兼容性好),Nacos类似。Spring Cloud Config需要配合Bus(MQ广播)实现热更新。

面试官:配置中心挂了怎么办?

你:客户端有多级降级:1)内存缓存 → 2)本地文件缓存 → 3)classpath默认配置。配置中心挂了不影响已启动的服务,只是无法获取最新配置。配置中心本身也要做高可用:多实例集群 + DB主从。