1 架构设计
上图简要描述了Apollo的总体设计,我们可以从下往上看:
Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端
Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
Config Service和Admin Service都是多实例、无状态部署,所以需要将自己注册到Eureka中并保持心跳
在Eureka之上我们架了一层Meta Server用于封装Eureka的服务发现接口
Client通过域名访问Meta Server获取Config Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Client侧会做load balance、错误重试
Portal通过域名访问Meta Server获取Admin Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Portal侧会做load balance、错误重试
为了简化部署,我们实际上会把Config Service、Eureka和Meta Server三个逻辑角色部署在同一个JVM进程中
2 工作原理
上图简要描述了Apollo客户端的实现原理:
客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。
客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。
这是一个fallback机制,为了防止推送机制失效导致配置不更新
客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified
定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
3. 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中
4. 客户端会把从服务端获取到的配置在本地文件系统缓存一份。在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
5. 应用程序从Apollo客户端获取最新的配置、订阅配置更新通知
3 与Spring集成原理
Spring的ApplicationContext会包含一个Environment,ConfigurableEnvironment自身包含了很多个PropertySource,
PropertySource可以理解为很多个Key - Value的属性配置。
在运行时的结构形如:
PropertySource之间是有优先级顺序的,如果有一个Key在多个property source中都存在,那么在前面的property source优先。
所以对上图的例子:
env.getProperty(“key1”) -> value1
env.getProperty(“key2”) -> value2
env.getProperty(“key3”) -> value4
Apollo和Spring/Spring Boot集成的手段:在应用启动阶段,Apollo从远端获取配置,然后组装成PropertySource并插入到第一个即可,如下图所示:
4、项目代码
4.1 实现
整个实现过程主要就三点:
1. 引入相关依赖
2. 项目启动添加@EnableApolloConfig
3.指定AppId、metaServer地址和运行环境
app.id=order.center.apollo.test
apollo.meta=http://localhost:8080
env=DEV
5、 配置更新
5.1 更新监听
日志监控配置变化,通过监听器实现
6.2.2 热更新测试
获取Apollo配置主要有三种方式:
1. api接口getProperty
通过改接口每次都会获取最新值,不存在更新延迟
2. @Value注解获取值
通过该注解获得的值会实时更新
AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: 4441, key: apollo.refresh.four, beanName: apolloTestBeanTwo, field: com.seeapp.center.order.controller.apollo.ApolloTestBeanTwo.four
3. @ConfigurationProperties注解的配置类
@ConfigurationProperties注解标注的配置类是不会实时更新的,需要在Apollo配置变化时自动更新注入的值,需要
@ApolloConfigChangeListener配合使用EnvironmentChangeEvent或RefreshScope。