更多内容参看官网文档:https://www.apolloconfig.com/#/zh/README
架构设计
- Config Service和Admin Service都是多实例、无状态部署,所以需要将自己注册到Eureka中并保持心跳
- 在Eureka之上我们架了一层Meta Server用于封装Eureka的服务发现接口
- Client通过域名访问Meta Server获取Config Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Client侧会做load balance、错误重试
七个模块
ConfigService
提供配置推送、获取接口,服务与Apollo客户端
AdminService
提供配置管理接口,服务于管理界面portal
Client
- 为应用获取配置,支持实时更新
- 为metaServer获取ConfigService的服务列表
- 使用客户端软负载SLB方式调用ConfigService
Portal
- 配置管理界面
- 通过mateServer获取AdminService的服务列表
- 使用客户端软负载SLB方式调用AdminService
Eureka
- 用于服务发现和注册
- Config/AdminService注册实例并报心跳
- 和ConfigService一起部署
MetaServer
- Portal通过域名访问MetaServer获取AdminService的地址列表
- Client通过域名访问MetaServer获取ConfigService的地址列表
- 相当于一个Eureka Proxy
- 和ConfigService一起部署
NginxLB
- 和域名系统配合,协助Portal访问MetaServer获取AdminService地址列表
- 和域名系统配合,协助Client访问MetaServer获取ConfigService地址列表
- 和域名系统配合,协助用户访问Portal进行配置管理
客户端设计
- 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)
- 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。
- 这是一个fallback机制,为了防止推送机制失效导致配置不更新
- 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified
- 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property:
apollo.refreshInterval
来覆盖,单位为分钟。
- 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中
- 客户端会把从服务端获取到的配置在本地文件系统缓存一份
- 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
- 应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知
和SpringBoot集成时,插入到ApplicationContext的Environment的PropertySources的第一条
配置更新推送
- 客户端发起Http请求到服务端
- 服务端会保持住这个链接60秒
- 如果60秒内有配置变化,请求会立即返回,并告知客户端有变化的namespace,客户端据此拉取配置
- 如果60秒内没有变化,返回HTTP状态码304
- 客户端收到服务端请求后会立即重新发起链接,回到第一步
核心概念
Namespace
服务可用性
Java API
获取配置
// 获取application namespace
Config config = ConfigService.getAppConfig();
// 获取非application namespace
Config config = ConfigService.getConfig(namespaceName);
Integer defaultRequestTimeout = 200;
Integer requestTimeout = config.getIntProperty("requestTimeout", defaultRequestTimeout);
监听配置变化
Config config = ConfigService.getAppConfig();
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
System.out.println(String.format(
"Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
change.getPropertyName(), change.getOldValue(),
change.getNewValue(), change.getChangeType()));
}
}
});