一句话总结
配置中心核心功能:配置管理(集中存储、环境隔离、版本管理)、配置热更新(长轮询/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. 灰度发布:配置逐步生效,降低风险
主流方案对比
| 方案 | 存储 | 热更新 | 特点 |
|---|---|---|---|
| Apollo | MySQL | 长轮询(1s) | 功能全面,携程开源 |
| Nacos | MySQL/Derby | 长轮询 | 配置+注册二合一 |
| Spring Cloud Config | Git/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主从。