Apollo — 分布式配置中心
架构设计
Apollo 是携程开源的分布式配置中心,专注于配置管理,提供完善的权限管控、灰度发布和审计功能。
┌──────────────────────────────────────────────────────────┐
│ Apollo Portal(管理界面) │
└──────────────────────┬───────────────────────────────────┘
│ 管理 API
┌──────────────────────▼───────────────────────────────────┐
│ Apollo Config Service │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ 配置读取 │ │ 配置推送 │ │ 灰度发布 │ │
│ └─────────────┘ └──────────────┘ └─────────────────┘ │
└──────────────────────┬───────────────────────────────────┘
│
┌──────────────────────▼───────────────────────────────────┐
│ MySQL(配置存储) │
└──────────────────────────────────────────────────────────┘
客户端:
App ──► Apollo Client ──[长轮询]──► Config Service
──[本地缓存]──► 本地文件(降级)核心概念
| 概念 | 说明 | 示例 |
|---|---|---|
| AppId | 应用唯一标识 | order-service |
| Environment | 环境 | DEV/FAT/UAT/PRO |
| Cluster | 集群(同环境不同配置) | default/beijing/shanghai |
| Namespace | 配置文件(类似文件) | application/database/redis |
配置优先级
远程配置(Apollo)> 本地配置文件(application.yml)Spring Boot 集成
xml
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>2.1.0</version>
</dependency>properties
# application.properties
app.id=order-service
apollo.meta=http://apollo-config:8080
apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=application,database,redis.properties
# 开启启动阶段注入(确保 @Value 在 Bean 初始化前就有值)
apollo.bootstrap.eagerLoad.enabled=truejava
// 使用 @Value 注入(需配合 @RefreshScope 或 ApolloConfigChangeListener)
@Component
public class OrderConfig {
@Value("${order.timeout:5000}")
private int timeout;
// 监听配置变更
@ApolloConfigChangeListener(value = {"application", "database"})
private void onChange(ConfigChangeEvent event) {
event.changedKeys().forEach(key -> {
ConfigChange change = event.getChange(key);
log.info("Config changed: {} {} -> {}",
key, change.getOldValue(), change.getNewValue());
});
// 手动刷新 Bean(如果没有 @RefreshScope)
refreshConfig();
}
}多 Namespace 使用
java
// 读取公共配置(跨应用共享)
@ApolloConfig("application")
private Config appConfig;
@ApolloConfig("common.properties") // 公共 Namespace
private Config commonConfig;
@PostConstruct
public void init() {
String dbUrl = commonConfig.getProperty("db.url", "default");
String timeout = appConfig.getProperty("order.timeout", "5000");
}灰度发布
Apollo 支持按 IP 灰度发布配置:
1. 在 Portal 创建灰度版本
2. 指定灰度 IP(如:192.168.1.100, 192.168.1.101)
3. 发布灰度版本
4. 验证灰度节点行为
5. 全量发布 或 回滚java
// 客户端无需特殊处理,Apollo 自动根据 IP 下发对应配置
// 灰度节点收到灰度配置,其他节点收到正式配置权限管控
Apollo 提供细粒度的权限控制:
| 权限 | 说明 |
|---|---|
| 项目管理员 | 管理项目成员、Namespace |
| 发布权限 | 可以发布配置(生产环境建议与编辑权限分离) |
| 编辑权限 | 可以修改配置,但不能发布 |
| 查看权限 | 只读 |
最佳实践:生产环境配置编辑和发布权限分离,避免误操作。
配置加密
敏感配置(密码、密钥)建议加密存储:
java
// 使用 jasypt 加密
// 1. 加密配置值
String encrypted = jasypt.encrypt("my-db-password");
// 存储:ENC(加密后的值)
// 2. Apollo 中存储:db.password=ENC(xxxxx)
// 3. 客户端自动解密
@SpringBootApplication
@EnableEncryptableProperties
public class Application { }高可用部署
生产环境推荐部署:
Config Service × 3(无状态,可水平扩展)
Admin Service × 2(无状态)
Portal × 1(或 2,主备)
MySQL × 1主1从(或 RDS)
Config Service 前置 Nginx/SLB 负载均衡nginx
# nginx.conf
upstream apollo-config {
server apollo-config-1:8080;
server apollo-config-2:8080;
server apollo-config-3:8080;
}故障处理案例
案例一:配置变更后客户端未更新
排查:
bash
# 检查客户端长轮询是否正常
# 客户端日志关键字
grep "Loaded config for namespace" application.log
grep "Config changed" application.log
# 检查 Config Service 是否正常
curl http://apollo-config:8080/health常见原因:
- 客户端与 Config Service 网络不通
apollo.meta配置错误- 客户端版本过旧,不支持长轮询
案例二:本地缓存导致读取旧配置
现象:Config Service 不可用时,客户端读取本地缓存文件,但缓存文件是旧版本。
本地缓存位置:
/opt/data/{appId}/config-cache/{appId}+{cluster}+{namespace}.properties处理:
- 正常情况:Config Service 恢复后,客户端自动同步最新配置
- 紧急情况:手动更新本地缓存文件,重启应用
案例三:数据库连接池耗尽
现象:Apollo Config Service 响应慢,日志出现数据库连接超时。
解决:
properties
# Config Service 数据库连接池配置
spring.datasource.hikari.maximum-pool-size=50
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.connection-timeout=30000与 Nacos 配置中心对比
| 维度 | Apollo | Nacos |
|---|---|---|
| 定位 | 专注配置管理 | 配置 + 服务发现 |
| 权限管控 | 细粒度(编辑/发布分离) | 基础权限 |
| 灰度发布 | 原生支持(按 IP) | 支持 Beta 发布 |
| 审计日志 | 完整操作记录 | 基础日志 |
| 多环境 | 原生多环境 | 命名空间隔离 |
| 配置格式 | Properties/XML/JSON/YAML/TXT | Properties/YAML/JSON/TEXT |
| 适用场景 | 大型团队,权限要求高 | 中小团队,一站式 |