apollo 配置中心_apollo配置中心

apollo学习

之前有看apollo的一些文档,但是过一段时间就忘记了,这里整理一下,方便以后查看吧。文章的资料来自于

https://github.com/ctripcorp/apollo。

Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

服务端基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器。

Java客户端不依赖任何框架,能够运行于所有Java运行时环境,同时对Spring/Spring Boot环境也有较好的支持。

一、apollo配置中心设计

1.1 基础模型

  1. 用户在配置中心对配置进行修改并发布

  2. 配置中心通知apollo客户端有配置更新

  3. apollo客户端从配置中心拉取最新的配置,更新本地配置并通知到应用

1.2 架构设计

1.2.1 架构设计图

29fc06c2edcbfcf69e34826f6a45aa60.png

1.2.2 四个核心模块及其主要功能

  1. configService

  • 提供配置获取接口

  • 提供配置推送接口

  • 服务于apollo客户端

adminService

  • 提供配置管理接口

  • 提供配置修改发布接口

  • 服务于管理界面portal

client

  • 为应用获取配置,支持实时更新

  • 通过MetaServer获取ConfigService的服务列表

  • 使用客户关软负载均衡SLB方式调用ConfigService

portal

  • 配置管理页面

  • 通过MetaServer获取AdminService的服务列表

  • 使用客户端软负载均衡SLB方式调用AdminService

1.2.3 三个辅助发现模块

  1. Eureka

  • 用户服务发现和注册

  • config/adminService注册实例并定期报心跳

  • 和ConfigService住在一起部署

MetaServer

  • portal通过域名访问MetaServer获取AdminService的地址列表

  • Client通过域名访问MetaServer获取ConfigService的地址列表

  • 相当于一个eureka

NginxLB

  • 和域名系统配合,协助portal访问MetaServer获取AdminService地址列表

  • 和域名系统配合,协助client访问MetaServer获取ConfigService地址列表

  • 和域名系统配合,协助用户访问Portal进行配置管理

1.3 E-R Diagram

1.3.1 主体E-R

  • app

    • App信息

  • appnamespace

    • App下Namespace的元信息

  • cluster

    • 集群信息

  • namespace

    • 集群下的namespace

  • item

    • Namespace的配置,每个Item是一个key, value组合

  • release

    • Namespace发布的配置,每个发布包含发布时该Namespace的所有配置

  • commit

    • Namespace下的配置更改记录

  • audit

    • 审计信息,记录用户在何时使用何种方式操作了哪个实体。

1.3.2 权限相关E-R Diagram

  • User

    • Apollo portal用户

  • UserRole

    • 用户和角色的关系

  • Role

    • 角色

  • RolePermission

    • 角色和权限的关系

  • Permission

    • 权限

    • 对应到具体的实体资源和操作,如修改NamespaceA的配置,发布NamespaceB的配置等。

  • Consumer

    • 第三方应用

  • ConsumerToken

    • 发给第三方应用的token

  • ConsumerRole

    • 第三方应用和角色的关系

  • ConsumerAudit

    • 第三方应用访问审计

二、服务端设计

在配置中心中,一个重要的功能就是配置发布过后实时推动到客户端。大致过程如下:

  1. 用户在Portal操作配置发布

  2. Portal调用Adminservice的接口操作发布

  3. Adminservice发布配置后,发送releaseMessage给各个ConfigService

  4. ConfigService收到releaseMessage后,通知对应的客户端

2.1.1 发送ReleaseMessage的实现方式

Admin Service在配置发布后,需要通知所有的Config Service有配置发布,从而Config Service可以通知对应的客户端来拉取最新的配置。

从概念上来看,这是一个典型的消息使用场景,Admin Service作为producer发出消息,各个Config Service作为consumer消费消息。通过一个消息组件(Message Queue)就能很好的实现Admin Service和Config Service的解耦。

在实现上,考虑到Apollo的实际使用场景,以及为了尽可能减少外部依赖,我们没有采用外部的消息中间件,而是通过数据库实现了一个简单的消息队列。

实现方式如下:

  1. Admin Service在配置发布后会往ReleaseMessage表插入一条消息记录,消息内容就是配置发布的AppId+Cluster+Namespace,参见DatabaseMessageSender

  2. Config Service有一个线程会每秒扫描一次ReleaseMessage表,看看是否有新的消息记录,参见ReleaseMessageScanner

  3. Config Service如果发现有新的消息记录,那么就会通知到所有的消息监听器(ReleaseMessageListener),如NotificationControllerV2,消息监听器的注册过程参见ConfigServiceAutoConfiguration

  4. NotificationControllerV2得到配置发布的AppId+Cluster+Namespace后,会通知对应的客户端

2.1.2 Config Service通知客户端的实现方式

上一节中简要描述了NotificationControllerV2是如何得知有配置发布的,那NotificationControllerV2在得知有配置发布后是如何通知到客户端的呢?

实现方式如下:

  1. 客户端会发起一个Http请求到Config Service的notifications/v2接口,也就是NotificationControllerV2,参见RemoteConfigLongPollService

  2. NotificationControllerV2不会立即返回结果,而是通过Spring DeferredResult把请求挂起

  3. 如果在60秒内没有该客户端关心的配置发布,那么会返回Http状态码304给客户端

  4. 如果有该客户端关心的配置发布,NotificationControllerV2会调用DeferredResult的setResult方法,传入有配置变化的namespace信息,同时该请求会立即返回。客户端从返回的结果中获取到配置变化的namespace后,会立即请求Config Service获取该namespace的最新配置。

三、客户端设计

上图简要描述了Apollo客户端的实现原理:

  1. 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)

  2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。

  • 这是一个fallback机制,为了防止推送机制失效导致配置不更新

  • 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified

  • 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。

客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中

客户端会把从服务端获取到的配置在本地文件系统缓存一份

  • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置

应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知

3.1 和Spring集成的原理

Apollo除了支持API方式获取配置,也支持和Spring/Spring Boot集成,集成原理简述如下。

Spring从3.1版本开始增加了ConfigurableEnvironmentPropertySource

  • ConfigurableEnvironment

    • Spring的ApplicationContext会包含一个Environment(实现ConfigurableEnvironment接口)

    • 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并插入到第一个即可

相关代码可以参考PropertySourcesProcessor

四、apollo分布式部署指南

4.1 数据库表创建

  • 新搭建时:

    执行sql文件:apolloportaldb.sql和apolloconfigdb.sql创建表

  • 从别的环境移植时

    主要讲将ApolloConfigDB.App。ApolloConfigDB.AppNamespace。ApolloConfigDB.Cluster。ApolloConfigDB.Namespace。这几个表中的数据加入到新表中。

    同时也别忘了通知用户在新的环境给自己的项目设置正确的配置信息,尤其是一些影响面比较大的公共namespace配置。

    如果是为正在运行的环境迁移数据,建议迁移完重启一下config service,因为config service中有appnamespace的缓存数据。

需要注意的是ApolloPortalDB只需要在生产环境部署一个即可,而ApolloConfigDB需要在每个环境部署一套,如fat、uat和pro分别部署3套ApolloConfigDB。

4.2 调整服务端配置

Apollo自身的一些配置是放在数据库里面的,所以需要针对实际情况做一些调整。

以下配置除了支持在数据库中配置以外,也支持通过-D参数、application.properties等配置,且-D参数、application.properties等优先级高于数据库中的配置

4.2.1 调整ApolloPortalDB配置

配置项统一存储在ApolloPortalDB.ServerConfig表中,也可以通过管理员工具 - 系统参数页面进行配置,无特殊说明则修改完一分钟实时生效。

  1. apollo.portal.envs - 可支持的环境列表

    DEV,FAT,UAT,PRO
  2. apollo.portal.meta.servers - 各环境Meta Service列表

    {
    "DEV":"http://1.1.1.1:8080",
    "FAT":"http://apollo.fat.xxx.com",
    "UAT":"http://apollo.uat.xxx.com",
    "PRO":"http://apollo.xxx.com"
    }
  3. superAdmin - Portal超级管理员

  4. organizations-部门列表

    [{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]
  5. configView.memberOnly.envs

    只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔.

    对设定了只对项目成员显示配置信息的环境,只有该项目的管理员或拥有该namespace的编辑或发布权限的用户才能看到该私有namespace的配置信息和发布历史。公共namespace始终对所有用户可见。

  6. role.manage-app-master.enabled - 是否开启项目管理员分配权限控制

    如果设置为true,那么只有超级管理员和拥有项目管理员分配权限的帐号可以为特定项目添加/删除管理员,超级管理员可以通过管理员工具 - 系统权限管理给用户分配特定项目的管理员分配权限.

  7. prefix.path - 设置Portal挂载到nginx/slb后的相对路径

    如果希望在Portal前挂软负载,一般情况下建议直接使用根目录来挂载,不过如果有些情况希望和其它应用共用nginx/slb,需要加上相对路径,那么可以配置此项,如prefix.path=/apollo,更多信息可以参考Portal挂载到nginx/slb后如何设置相对路径?。

4.2.2 调整ApolloConfigDB配置

配置项统一存储在ApolloConfigDB.ServerConfig表中,需要注意每个环境的ApolloConfigDB.ServerConfig都需要单独配置,修改完一分钟实时生效。

1. eureka.service.url - Eureka服务Url

不管是apollo-configservice还是apollo-adminservice都需要向eureka服务注册,所以需要配置eureka服务地址。按照目前的实现,apollo-configservice本身就是一个eureka服务,所以只需要填入apollo-configservice的地址即可,如有多个,用逗号分隔(注意不要忘了/eureka/后缀)。

需要注意的是每个环境只填入自己环境的eureka服务地址,比如FAT的apollo-configservice是1.1.1.1:8080和2.2.2.2:8080,UAT的apollo-configservice是3.3.3.3:8080和4.4.4.4:8080,PRO的apollo-configservice是5.5.5.5:8080和6.6.6.6:8080,那么:

  1. 在FAT环境的ApolloConfigDB.ServerConfig表中设置eureka.service.url为:

http://1.1.1.1:8080/eureka/,http://2.2.2.2:8080/eureka/
  1. 在UAT环境的ApolloConfigDB.ServerConfig表中设置eureka.service.url为:

http://3.3.3.3:8080/eureka/,http://4.4.4.4:8080/eureka/
  1. 在PRO环境的ApolloConfigDB.ServerConfig表中设置eureka.service.url为:

http://5.5.5.5:8080/eureka/,http://6.6.6.6:8080/eureka/

注意:这里需要填写本环境中全部的eureka服务地址,因为eureka需要互相复制注册信息

如果希望将Config Service和Admin Service注册到公司统一的Eureka上,可以参考部署&开发遇到的常见问题 - 将Config Service和Admin Service注册到单独的Eureka Server上章节

在多机房部署时,往往希望config service和admin service只向同机房的eureka注册,要实现这个效果,需要利用ServerConfig表中的cluster字段,config service和admin service会读取所在机器的/opt/settings/server.properties(Mac/Linux)或C:\opt\settings\server.properties(Windows)中的idc属性,如果该idc有对应的eureka.service.url配置,那么就只会向该机房的eureka注册。比如config service和admin service会部署到SHAOYSHAJQ两个IDC,那么为了实现这两个机房中的服务只向该机房注册,那么可以在ServerConfig表中新增两条记录,分别填入SHAOYSHAJQ两个机房的eureka地址即可,default cluster的记录可以保留,如果有config service和admin service不是部署在SHAOYSHAJQ这两个机房的,就会使用这条默认配置。

KeyClusterValueComment
eureka.service.urldefaulthttp://1.1.1.1:8080/eureka/默认的Eureka服务Url
eureka.service.urlSHAOYhttp://2.2.2.2:8080/eureka/SHAOY的Eureka服务Url
eureka.service.urlSHAJQhttp://3.3.3.3:8080/eureka/SHAJQ的Eureka服务Url
2.namespace.lock.switch - 一次发布只能有一个人修改开关,用于发布审核

这是一个功能开关,如果配置为true的话,那么一次配置发布只能是一个人修改,另一个发布。

生产环境建议开启此选项

3. config-service.cache.enabled - 是否开启配置缓存

这是一个功能开关,如果配置为true的话,config service会缓存加载过的配置信息,从而加快后续配置获取性能。

默认为false,开启前请先评估总配置大小并调整config service内存配置。

开启缓存后必须确保应用中配置的app.id大小写正确,否则将获取不到正确的配置

4. item.key.length.limit - 配置项 key 最大长度限制

默认配置是128。

5. item.value.length.limit - 配置项 value 最大长度限制

默认配置是20000。

4.3 获取安装包

可以通过两种方式获取安装包:

  1. 直接下载安装包

  • 从GitHub Release页面下载预先打好的安装包

  • 如果对Apollo的代码没有定制需求,建议使用这种方式,可以省去本地打包的过程

通过源码构建

  • 从GitHub Release页面下载Source code包或直接clone源码后在本地构建

  • 如果需要对Apollo的做定制开发,需要使用这种方式

4.3.1 直接下载安装包

1.获取安装包

从GitHub Release页面下载最新版本的apollo-configservice-x.x.x-github.zipapollo-adminservice-x.x.x-github.zipapollo-portal-x.x.x-github.zip即可。

2.配置数据库连接信息

Apollo服务端需要知道如何连接到你前面创建的数据库,数据库连接串信息位于上一步下载的压缩包中的config/application-github.properties中。

2.1 配置apollo-configservice的数据库连接信息
spring.datasource.url = jdbc:mysql://localhost:3306/ApolloConfigDB?useSSL=false&characterEncoding=utf8
spring.datasource.username = someuser
spring.datasource.password = somepwd

注:由于ApolloConfigDB在每个环境都有部署,所以对不同的环境config-service需要配置对应环境的数据库参数

2.2 配置apollo-adminservice的数据库连接信息
# DataSource
spring.datasource.url = jdbc:mysql://localhost:3306/ApolloConfigDB?useSSL=false&characterEncoding=utf8
spring.datasource.username = someuser
spring.datasource.password = somepwd

注:由于ApolloConfigDB在每个环境都有部署,所以对不同的环境admin-service需要配置对应环境的数据库参数

2.3 配置apollo-portal的数据库连接信息
# DataSource
spring.datasource.url = jdbc:mysql://localhost:3306/ApolloPortalDB?useSSL=false&characterEncoding=utf8
spring.datasource.username = someuser
spring.datasource.password = somepwd
2.4 配置apollo-portal的meta service信息

Apollo Portal需要在不同的环境访问不同的meta service(apollo-configservice)地址,所以我们需要在配置中提供这些信息。默认情况下,meta service和config service是部署在同一个JVM进程,所以meta service的地址就是config service的地址。

打开apollo-portal-x.x.x-github.zipconfig目录下的apollo-env.properties文件。

dev.meta=http://1.1.1.1:8080
fat.meta=http://apollo.fat.xxx.com
uat.meta=http://apollo.uat.xxx.com
pro.meta=http://apollo.xxx.com

除了通过apollo-env.properties方式配置meta service以外,apollo也支持在运行时指定meta service(优先级比apollo-env.properties高):

  1. 通过Java System Property

    ${env}_meta
  • 可以通过Java的System Property ${env}_meta来指定,如java -Ddev_meta=http://config-service-url -jar xxx.jar

  • 也可以通过程序指定,如System.setProperty("dev_meta", "http://config-service-url");

通过操作系统的System Environment

${ENV}_META
  • DEV_META=http://config-service-url

  • 注意key为全大写,且中间是_分隔

注1: 为了实现meta service的高可用,推荐通过SLB(Software Load Balancer)做动态负载均衡

注2: meta service地址也可以填入IP,0.11.0版本之前只支持填入一个IP。从0.11.0版本开始支持填入以逗号分隔的多个地址(PR #1214),如http://1.1.1.1:8080,http://2.2.2.2:8080,不过生产环境还是建议使用域名(走slb),因为机器扩容、缩容等都可能导致IP列表的变化。

4.3.2 通过源码构建

1.配置数据库连接信息

Apollo服务端需要知道如何连接到你前面创建的数据库,所以需要编辑scripts/build.sh,修改ApolloPortalDB和ApolloConfigDB相关的数据库连接串信息。

注意:填入的用户需要具备对ApolloPortalDB和ApolloConfigDB数据的读写权限。

#apollo config db info
apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?useSSL=false&characterEncoding=utf8
apollo_config_db_username=用户名
apollo_config_db_password=密码(如果没有密码,留空即可)

# apollo portal db info
apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?useSSL=false&characterEncoding=utf8
apollo_portal_db_username=用户名
apollo_portal_db_password=密码(如果没有密码,留空即可)

注1:由于ApolloConfigDB在每个环境都有部署,所以对不同的环境config-service和admin-service需要使用不同的数据库参数打不同的包,portal只需要打一次包即可

注2:如果不想config-service和admin-service每个环境打一个包的话,也可以通过运行时传入数据库连接串信息实现,具体可以参考 Issue 869

注3:每个环境都需要独立部署一套config-service、admin-service和ApolloConfigDB

2.配置各环境meta service地址

编辑scripts/build.sh,如下修改各环境meta service服务地址,格式为${env}_meta=http://${config-service-url:port},如果某个环境不需要,也可以直接删除对应的配置项:

dev_meta=http://1.1.1.1:8080
fat_meta=http://apollo.fat.xxx.com
uat_meta=http://apollo.uat.xxx.com
pro_meta=http://apollo.xxx.com

META_SERVERS_OPTS="-Ddev_meta=$dev_meta -Dfat_meta=$fat_meta -Duat_meta=$uat_meta -Dpro_meta=$pro_meta"

除了在打包时配置meta service以外,apollo也支持在运行时指定meta service:

  1. 通过Java System Property

    ${env}_meta
  • 可以通过Java的System Property ${env}_meta来指定,如java -Ddev_meta=http://config-service-url -jar xxx.jar

  • 也可以通过程序指定,如System.setProperty("dev_meta", "http://config-service-url");

通过操作系统的System Environment

${ENV}_META
  • DEV_META=http://config-service-url

  • 注意key为全大写,且中间是_分隔

注1: 为了实现meta service的高可用,推荐通过SLB(Software Load Balancer)做动态负载均衡

注2: meta service地址也可以填入IP,0.11.0版本之前只支持填入一个IP。从0.11.0版本开始支持填入以逗号分隔的多个地址(PR #1214),如http://1.1.1.1:8080,http://2.2.2.2:8080,不过生产环境还是建议使用域名(走slb),因为机器扩容、缩容等都可能导致IP列表的变化。

4.3.3 执行编译、打包

做完上述配置后,就可以执行编译和打包了。

注:初次编译会从Maven中央仓库下载不少依赖,如果网络情况不佳时很容易出错,建议使用国内的Maven仓库源,比如阿里云Maven镜像

./build.sh

该脚本会依次打包apollo-configservice, apollo-adminservice, apollo-portal。

注:由于ApolloConfigDB在每个环境都有部署,所以对不同环境的config-service和admin-service需要使用不同的数据库连接信息打不同的包,portal只需要打一次包即可。

  1. 获取apollo-configservice安装包

    位于apollo-configservice/target/目录下的apollo-configservice-x.x.x-github.zip

    需要注意的是由于ApolloConfigDB在每个环境都有部署,所以对不同环境的config-service需要使用不同的数据库参数打不同的包后分别部署

  2. 获取apollo-adminservice安装包

    位于apollo-adminservice/target/目录下的apollo-adminservice-x.x.x-github.zip

    需要注意的是由于ApolloConfigDB在每个环境都有部署,所以对不同环境的admin-service需要使用不同的数据库参数打不同的包后分别部署

  3. 获取apollo-portal安装包

    位于apollo-portal/target/目录下的apollo-portal-x.x.x-github.zip

4.4 部署apollo服务端

4.4.1 部署apollo-configservice

将对应环境的apollo-configservice-x.x.x-github.zip上传到服务器上,解压后执行scripts/startup.sh即可。如需停止服务,执行scripts/shutdown.sh

记得在scripts/startup.sh中按照实际的环境设置一个JVM内存,以下是我们的默认设置,供参考:

export JAVA_OPTS="-server -Xms6144m -Xmx6144m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=4096m -XX:MaxNewSize=4096m -XX:SurvivorRatio=18"

注1:如果需要修改JVM参数,可以修改scripts/startup.sh的JAVA_OPTS部分。

注2:如要调整服务的日志输出路径,可以修改scripts/startup.sh和apollo-configservice.conf中的LOG_DIR

注3:如要调整服务的监听端口,可以修改scripts/startup.sh中的SERVER_PORT。另外apollo-configservice同时承担meta server职责,如果要修改端口,注意要同时ApolloConfigDB.ServerConfig表中的eureka.service.url配置项以及apollo-portal和apollo-client中的使用到的meta server信息,详见:2.2.1.2.4 配置apollo-portal的meta service信息和1.2.2 Apollo Meta Server。

注4:如果ApolloConfigDB.ServerConfig的eureka.service.url只配了当前正在启动的机器的话,在启动apollo-configservice的过程中会在日志中输出eureka注册失败的信息,如com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused。需要注意的是,这个是预期的情况,因为apollo-configservice需要向Meta Server(它自己)注册服务,但是因为在启动过程中,自己还没起来,所以会报这个错。后面会进行重试的动作,所以等自己服务起来后就会注册正常了。

4.4.2 部署apollo-adminservice

将对应环境的apollo-adminservice-x.x.x-github.zip上传到服务器上,解压后执行scripts/startup.sh即可。如需停止服务,执行scripts/shutdown.sh.

记得在scripts/startup.sh中按照实际的环境设置一个JVM内存,以下是我们的默认设置,供参考:

export JAVA_OPTS="-server -Xms2560m -Xmx2560m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=1024m -XX:MaxNewSize=1024m -XX:SurvivorRatio=22"

注1:如果需要修改JVM参数,可以修改scripts/startup.sh的JAVA_OPTS部分。

注2:如要调整服务的日志输出路径,可以修改scripts/startup.sh和apollo-adminservice.conf中的LOG_DIR

注3:如要调整服务的监听端口,可以修改scripts/startup.sh中的SERVER_PORT

4.4.3 部署apollo-portal

apollo-portal-x.x.x-github.zip上传到服务器上,解压后执行scripts/startup.sh即可。如需停止服务,执行scripts/shutdown.sh.

记得在startup.sh中按照实际的环境设置一个JVM内存,以下是我们的默认设置,供参考:

export JAVA_OPTS="-server -Xms4096m -Xmx4096m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=1536m -XX:MaxNewSize=1536m -XX:SurvivorRatio=22"

注1:如果需要修改JVM参数,可以修改scripts/startup.sh的JAVA_OPTS部分。

注2:如要调整服务的日志输出路径,可以修改scripts/startup.sh和apollo-portal.conf中的LOG_DIR

注3:如要调整服务的监听端口,可以修改scripts/startup.sh中的SERVER_PORT

五、java客户端使用指南

5.1 准备工作

Apollo客户端依赖于AppIdApollo Meta Server等环境信息来工作,所以请确保阅读下面的说明并且做正确的配置:

5.1.1 AppId

AppId是应用的身份信息,是从服务端获取配置的一个重要信息。

有以下几种方式设置,按照优先级从高到低分别为:

  1. System Property

Apollo 0.7.0+支持通过System Property传入app.id信息,如

-Dapp.id=YOUR-APP-ID
  1. 操作系统的System Environment

Apollo 1.4.0+支持通过操作系统的System Environment APP_ID来传入app.id信息,如

APP_ID=YOUR-APP-ID
  1. Spring Boot application.properties

Apollo 1.0.0+支持通过Spring Boot的application.properties文件配置,如

app.id=YOUR-APP-ID

该配置方式不适用于多个war包部署在同一个tomcat的使用场景

  1. app.properties

确保classpath:/META-INF/app.properties文件存在,并且其中内容形如:

app.id=YOUR-APP-ID

注:app.id是用来标识应用身份的唯一id,格式为string。

5.1.2 Apollo Meta Server

Apollo支持应用在不同的环境有不同的配置,所以需要在运行提供给Apollo客户端当前环境的Apollo Meta Server信息。默认情况下,meta server和config service是部署在同一个JVM进程,所以meta server的地址就是config service的地址。

为了实现meta server的高可用,推荐通过SLB(Software Load Balancer)做动态负载均衡。Meta server地址也可以填入IP,如http://1.1.1.1:8080,http://2.2.2.2:8080,不过生产环境还是建议使用域名(走slb),因为机器扩容、缩容等都可能导致IP列表的变化。

1.0.0版本开始支持以下方式配置apollo meta server信息,按照优先级从高到低分别为:

  1. 通过Java System Property

apollo.meta
  • 可以通过Java的System Property apollo.meta来指定

  • 在Java程序启动脚本中,可以指定

    -Dapollo.meta=http://config-service-url
    • 如果是运行jar文件,需要注意格式是java -Dapollo.meta=http://config-service-url -jar xxx.jar

  • 也可以通过程序指定,如System.setProperty("apollo.meta", "http://config-service-url");

  1. 通过Spring Boot的配置文件

  • 可以在Spring Boot的application.propertiesbootstrap.properties中指定apollo.meta=http://config-service-url

该配置方式不适用于多个war包部署在同一个tomcat的使用场景

  1. 通过操作系统的System Environment

    APOLLO_META
  • 可以通过操作系统的System Environment APOLLO_META来指定

  • 注意key为全大写,且中间是_分隔

通过

server.properties

配置文件

  • 可以在server.properties配置文件中指定apollo.meta=http://config-service-url

  • 对于Mac/Linux,文件位置为/opt/settings/server.properties

  • 对于Windows,文件位置为C:\opt\settings\server.properties

通过

app.properties

配置文件

  • 可以在classpath:/META-INF/app.properties指定apollo.meta=http://config-service-url

通过Java system property

${env}_meta
  • 如果当前env是dev,那么用户可以配置-Ddev_meta=http://config-service-url

  • 使用该配置方式,那么就必须要正确配置Environment,详见1.2.4.1 Environment

  1. 通过操作系统的System Environment

${ENV}_META

(1.2.0版本开始支持)

  • 如果当前env是dev,那么用户可以配置操作系统的System Environment DEV_META=http://config-service-url

  • 注意key为全大写

  • 使用该配置方式,那么就必须要正确配置Environment,详见1.2.4.1 Environment

  1. 通过

    apollo-env.properties

    文件

  • 用户也可以创建一个apollo-env.properties,放在程序的classpath下,或者放在spring boot应用的config目录下

  • 使用该配置方式,那么就必须要正确配置Environment,详见1.2.4.1 Environment

  • 文件内容形如:

dev.meta=http://1.1.1.1:8080
fat.meta=http://apollo.fat.xxx.com
uat.meta=http://apollo.uat.xxx.com
pro.meta=http://apollo.xxx.com

如果通过以上各种手段都无法获取到Meta Server地址,Apollo最终会fallback到http://apollo.meta作为Meta Server地址

5.1.2.1 自定义Apollo Meta Server地址定位逻辑

在1.0.0版本中,Apollo提供了MetaServerProvider SPI,用户可以注入自己的MetaServerProvider来自定义Meta Server地址定位逻辑。

由于我们使用典型的Java Service Loader模式,所以实现起来还是比较简单的。

有一点需要注意的是,apollo会在运行时按照顺序遍历所有的MetaServerProvider,直到某一个MetaServerProvider提供了一个非空的Meta Server地址,因此用户需要格外注意自定义MetaServerProvider的Order。规则是较小的Order具有较高的优先级,因此Order=0的MetaServerProvider会排在Order=1的MetaServerProvider的前面。

如果你的公司有很多应用需要接入Apollo,建议封装一个jar包,然后提供自定义的Apollo Meta Server定位逻辑,从而可以让接入Apollo的应用零配置使用。比如自己写一个xx-company-apollo-client,该jar包依赖apollo-client,在该jar包中通过spi方式定义自定义的MetaServerProvider实现,然后应用直接依赖xx-company-apollo-client即可。

MetaServerProvider的实现可以参考LegacyMetaServerProvider和DefaultMetaServerProvider。

5.1.2.2 跳过Apollo Meta Server服务发现

适用于apollo-client 0.11.0及以上版本

一般情况下都建议使用Apollo的Meta Server机制来实现Config Service的服务发现,从而可以实现Config Service的高可用。不过apollo-client也支持跳过Meta Server服务发现,主要用于以下场景:

  1. Config Service部署在公有云上,注册到Meta Server的是内网地址,本地开发环境无法直接连接

  2. Config Service部署在docker环境中,注册到Meta Server的是docker内网地址,本地开发环境无法直接连接

  3. Config Service部署在kubernetes中,希望使用kubernetes自带的服务发现能力(Service)

针对以上场景,可以通过直接指定Config Service地址的方式来跳过Meta Server服务发现,按照优先级从高到低分别为:

  1. 通过Java System Property

apollo.configService
  • 可以通过Java的System Property apollo.configService来指定

  • 在Java程序启动脚本中,可以指定

    -Dapollo.configService=http://config-service-url:port
    • 如果是运行jar文件,需要注意格式是java -Dapollo.configService=http://config-service-url:port -jar xxx.jar

  • 也可以通过程序指定,如System.setProperty("apollo.configService", "http://config-service-url:port");

  1. 通过操作系统的System Environment

    APOLLO_CONFIGSERVICE
  • 可以通过操作系统的System Environment APOLLO_CONFIGSERVICE来指定

  • 注意key为全大写,且中间是_分隔

通过

server.properties

配置文件

  • 可以在server.properties配置文件中指定apollo.configService=http://config-service-url:port

  • 对于Mac/Linux,文件位置为/opt/settings/server.properties

  • 对于Windows,文件位置为C:\opt\settings\server.properties

5.1.3 本地缓存路径

Apollo客户端会把从服务端获取到的配置在本地文件系统缓存一份,用于在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置,不影响应用正常运行。

本地缓存路径默认位于以下路径,所以请确保/opt/dataC:\opt\data\目录存在,且应用有读写权限。

  • Mac/Linux: /opt/data/{appId}/config-cache

  • Windows: C:\opt\data{appId}\config-cache

本地配置文件会以下面的文件名格式放置于本地缓存路径下:

*{appId}+{cluster}+{namespace}.properties*

  • appId就是应用自己的appId,如100004458

  • cluster就是应用使用的集群,一般在本地模式下没有做过配置的话,就是default

    namespace就是应用使用的配置namespace,一般是application 

  • 文件内容以properties格式存储,比如如果有两个key,一个是request.timeout,另一个是batch,那么文件内容就是如下格式:

request.timeout=2000
batch=2000
5.1.3.1 自定义缓存路径

1.0.0版本开始支持以下方式自定义缓存路径,按照优先级从高到低分别为:

  1. 通过Java System Property

    apollo.cacheDir
  • 如果是运行jar文件,需要注意格式是java -Dapollo.cacheDir=/opt/data/some-cache-dir -jar xxx.jar

  • 可以通过Java的System Property apollo.cacheDir来指定

  • 在Java程序启动脚本中,可以指定

    -Dapollo.cacheDir=/opt/data/some-cache-dir
  • 也可以通过程序指定,如System.setProperty("apollo.cacheDir", "/opt/data/some-cache-dir");

通过Spring Boot的配置文件

  • 可以在Spring Boot的application.propertiesbootstrap.properties中指定apollo.cacheDir=/opt/data/some-cache-dir

通过操作系统的System Environment

APOLLO_CACHEDIR
  • 可以通过操作系统的System Environment APOLLO_CACHEDIR来指定

  • 注意key为全大写,且中间是_分隔

通过

server.properties

配置文件

  • 可以在server.properties配置文件中指定apollo.cacheDir=/opt/data/some-cache-dir

  • 对于Mac/Linux,文件位置为/opt/settings/server.properties

  • 对于Windows,文件位置为C:\opt\settings\server.properties

注:本地缓存路径也可用于容灾目录,如果应用在所有config service都挂掉的情况下需要扩容,那么也可以先把配置从已有机器上的缓存路径复制到新机器上的相同缓存路径

5.1.4 可选配置

5.1.4.1 Environment

Environment可以通过以下3种方式的任意一个配置:

  1. 通过Java System Property

  • 如果是运行jar文件,需要注意格式是java -Denv=YOUR-ENVIRONMENT -jar xxx.jar

  • 可以通过Java的System Property env来指定环境

  • 在Java程序启动脚本中,可以指定

    -Denv=YOUR-ENVIRONMENT
  • 注意key为全小写

通过操作系统的System Environment

  • 还可以通过操作系统的System Environment ENV来指定

  • 注意key为全大写

通过配置文件

  • 最后一个推荐的方式是通过配置文件来指定env=YOUR-ENVIRONMENT

  • 对于Mac/Linux,文件位置为/opt/settings/server.properties

  • 对于Windows,文件位置为C:\opt\settings\server.properties

文件内容形如:

env=DEV

目前,env支持以下几个值(大小写不敏感):

  • DEV

    • Development environment

  • FAT

    • Feature Acceptance Test environment

  • UAT

    • User Acceptance Test environment

  • PRO

    • Production environment

更多环境定义,可以参考Env.java

5.1.4.2 Cluster(集群)

Apollo支持配置按照集群划分,也就是说对于一个appId和一个环境,对不同的集群可以有不同的配置。

1.0.0版本开始支持以下方式集群,按照优先级从高到低分别为:

  1. 通过Java System Property

apollo.cluster
  • 可以通过Java的System Property apollo.cluster来指定

  • 在Java程序启动脚本中,可以指定

    -Dapollo.cluster=SomeCluster
    • 如果是运行jar文件,需要注意格式是java -Dapollo.cluster=SomeCluster -jar xxx.jar

  • 也可以通过程序指定,如System.setProperty("apollo.cluster", "SomeCluster");

  1. 通过Spring Boot的配置文件

  • 可以在Spring Boot的application.propertiesbootstrap.properties中指定apollo.cluster=SomeCluster

通过Java System Property

  • 如果是运行jar文件,需要注意格式是java -Didc=xxx -jar xxx.jar

  • 可以通过Java的System Property idc来指定环境

  • 在Java程序启动脚本中,可以指定

    -Didc=xxx
  • 注意key为全小写

通过操作系统的System Environment

  • 还可以通过操作系统的System Environment IDC来指定

  • 注意key为全大写

通过

server.properties

配置文件

  • 可以在server.properties配置文件中指定idc=xxx

  • 对于Mac/Linux,文件位置为/opt/settings/server.properties

  • 对于Windows,文件位置为C:\opt\settings\server.properties

Cluster Precedence(集群顺序)

  1. 如果apollo.clusteridc同时指定:

  • 我们会首先尝试从apollo.cluster指定的集群加载配置

  • 如果没找到任何配置,会尝试从idc指定的集群加载配置

  • 如果还是没找到,会从默认的集群(default)加载

如果只指定了apollo.cluster

  • 我们会首先尝试从apollo.cluster指定的集群加载配置

  • 如果没找到,会从默认的集群(default)加载

如果只指定了idc

  • 我们会首先尝试从idc指定的集群加载配置

  • 如果没找到,会从默认的集群(default)加载

如果apollo.clusteridc都没有指定:

  • 我们会从默认的集群(default)加载配置

5.1.4.3 设置内存中的配置项是否保持和页面上的顺序一致

适用于1.6.0及以上版本

默认情况下,apollo client内存中的配置存放在Properties中(底下是Hashtable),不会刻意保持和页面上看到的顺序一致,对绝大部分的场景是没有影响的。不过有些场景会强依赖配置项的顺序(如spring cloud zuul的路由规则),针对这种情况,可以开启OrderedProperties特性来使得内存中的配置顺序和页面上看到的一致。

配置方式按照优先级从高到低分别为:

  1. 通过Java System Property

apollo.property.order.enable
  • 可以通过Java的System Property apollo.property.order.enable来指定

  • 在Java程序启动脚本中,可以指定

    -Dapollo.property.order.enable=true
    • 如果是运行jar文件,需要注意格式是java -Dapollo.property.order.enable=true -jar xxx.jar

  • 也可以通过程序指定,如System.setProperty("apollo.property.order.enable", "true");

  1. 通过Spring Boot的配置文件

  • 可以在Spring Boot的application.propertiesbootstrap.properties中指定apollo.property.order.enable=true

通过

app.properties

配置文件

  • 可以在classpath:/META-INF/app.properties指定apollo.property.order.enable=true

5.1.4.4 配置访问秘钥

适用于1.6.0及以上版本

Apollo从1.6.0版本开始增加访问秘钥机制,从而只有经过身份验证的客户端才能访问敏感配置。如果应用开启了访问秘钥,客户端需要配置秘钥,否则无法获取配置。

配置方式按照优先级从高到低分别为:

  1. 通过Java System Property

apollo.accesskey.secret
  • 可以通过Java的System Property apollo.accesskey.secret来指定

  • 在Java程序启动脚本中,可以指定

    -Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719
    • 如果是运行jar文件,需要注意格式是java -Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719 -jar xxx.jar

  • 也可以通过程序指定,如System.setProperty("apollo.accesskey.secret", "1cf998c4e2ad4704b45a98a509d15719");

  1. 通过Spring Boot的配置文件

  • 可以在Spring Boot的application.propertiesbootstrap.properties中指定apollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719

通过操作系统的System Environment

  • 还可以通过操作系统的System Environment APOLLO_ACCESSKEY_SECRET来指定

  • 注意key为全大写

通过

app.properties

配置文件

  • 可以在classpath:/META-INF/app.properties指定apollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719

5.2 Maven Dependency

Apollo的客户端jar包已经上传到中央仓库,应用在实际使用时只需要按照如下方式引入即可。

    <dependency>
<groupId>com.ctrip.framework.apollogroupId>
<artifactId>apollo-clientartifactId>
<version>1.1.0version>
dependency>

5.3 Springboot集成方式的客户端

支持通过application.properties/bootstrap.properties来配置,该方式能使配置在更早的阶段注入,比如使用@ConditionalOnProperty的场景或者是有一些spring-boot-starter在启动阶段就需要读取配置做一些事情(如dubbo-spring-boot-project),所以对于Spring Boot环境建议通过以下方式来接入Apollo(需要0.10.0及以上版本)。

使用方式很简单,只需要在application.properties/bootstrap.properties中按照如下样例配置即可。

  1. 注入默认application namespace的配置示例

     # will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
  1. 注入非默认application namespace或多个namespace的配置示例

     apollo.bootstrap.enabled = true
# will inject 'application', 'FX.apollo' and 'application.yml' namespaces in bootstrap phase
apollo.bootstrap.namespaces = application,FX.apollo,application.yml
  1. 将Apollo配置加载提到初始化日志系统之前(1.2.0+)

从1.2.0版本开始,如果希望把日志相关的配置(如logging.level.root=infologback-spring.xml中的参数)也放在Apollo管理,那么可以额外配置apollo.bootstrap.eagerLoad.enabled=true来使Apollo的加载顺序放到日志系统加载之前,不过这会导致Apollo的启动过程无法通过日志的方式输出(因为执行Apollo加载的时候,日志系统压根没有准备好呢!所以在Apollo代码中使用Slf4j的日志输出便没有任何内容),更多信息可以参考PR 1614。参考配置示例如下:

     # will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
# put apollo initialization before logging system initialization
apollo.bootstrap.eagerLoad.enabled=true

5.4 Spring Placeholder的使用

Spring应用通常会使用Placeholder来注入配置,使用的格式形如${someKey:someDefaultValue},如${timeout:100}。冒号前面的是key,冒号后面的是默认值。

建议在实际使用时尽量给出默认值,以免由于key没有定义导致运行时错误。

从v0.10.0开始的版本支持placeholder在运行时自动更新,具体参见PR #972。

如果需要关闭placeholder在运行时自动更新功能,可以通过以下两种方式关闭:

  1. 通过设置System Property apollo.autoUpdateInjectedSpringProperties,如启动时传入-Dapollo.autoUpdateInjectedSpringProperties=false

  2. 通过设置META-INF/app.properties中的apollo.autoUpdateInjectedSpringProperties属性,如

app.id=SampleApp
apollo.autoUpdateInjectedSpringProperties=false

5.4.1 Java Config使用方式

通过Java Config的方式还可以使用@Value的方式注入:

public class TestJavaConfigBean {
@Value("${timeout:100}")
private int timeout;
private int batch;

@Value("${batch:200}")
public void setBatch(int batch) {
this.batch = batch;
}

public int getTimeout() {
return timeout;
}

public int getBatch() {
return batch;
}
}

在Configuration类中按照下面的方式使用(假设应用默认的application namespace中有timeoutbatch的配置项):

@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}

5.4.2 ConfigurationProperties使用方式

Spring Boot提供了@ConfigurationProperties把配置注入到bean对象中。

Apollo也支持这种方式,下面的例子会把redis.cache.expireSecondsredis.cache.commandTimeout分别注入到SampleRedisConfig的expireSecondscommandTimeout字段中。

@ConfigurationProperties(prefix = "redis.cache")
public class SampleRedisConfig {
private int expireSeconds;
private int commandTimeout;

public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}

public void setCommandTimeout(int commandTimeout) {
this.commandTimeout = commandTimeout;
}
}

在Configuration类中按照下面的方式使用(假设应用默认的application namespace中有redis.cache.expireSecondsredis.cache.commandTimeout的配置项):

@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public SampleRedisConfig sampleRedisConfig() {
return new SampleRedisConfig();
}
}

需要注意的是,@ConfigurationProperties如果需要在Apollo配置变化时自动更新注入的值,需要配合使用EnvironmentChangeEvent或RefreshScope。相关代码实现,可以参考apollo-use-cases项目中的ZuulPropertiesRefresher.java和apollo-demo项目中的SampleRedisConfig.java以及SpringBootApolloRefreshConfig.java

5.4.3 Spring Annotation支持

Apollo同时还增加了几个新的Annotation来简化在Spring环境中的使用。

  1. @ApolloConfig

  • 用来自动注入Config对象

@ApolloConfigChangeListener

  • 用来自动注册ConfigChangeListener

@ApolloJsonValue

  • 用来把配置的json字符串自动注入为对象

使用样例如下:

public class TestApolloAnnotationBean {
@ApolloConfig
private Config config; //inject config for namespace application
@ApolloConfig("application")
private Config anotherConfig; //inject config for namespace application
@ApolloConfig("FX.apollo")
private Config yetAnotherConfig; //inject config for namespace FX.apollo
@ApolloConfig("application.yml")
private Config ymlConfig; //inject config for namespace application.yml

/**
* ApolloJsonValue annotated on fields example, the default value is specified as empty list - []
*
* jsonBeanProperty=[{"someString":"hello","someInt":100},{"someString":"world!","someInt":200}]
*/
@ApolloJsonValue("${jsonBeanProperty:[]}")
private List anotherJsonBeans;@Value("${batch:100}")private int batch;//config change listener for namespace application@ApolloConfigChangeListenerprivate void someOnChange(ConfigChangeEvent changeEvent) {//update injected value of batch if it is changed in Apolloif (changeEvent.isChanged("batch")) {
batch = config.getIntProperty("batch", 100);
}
}//config change listener for namespace application@ApolloConfigChangeListener("application")private void anotherOnChange(ConfigChangeEvent changeEvent) {//do something
}//config change listener for namespaces application, FX.apollo and application.yml@ApolloConfigChangeListener({"application", "FX.apollo", "application.yml"})private void yetAnotherOnChange(ConfigChangeEvent changeEvent) {//do something
}//example of getting config from Apollo directly//this will always return the latest value of timeoutpublic int getTimeout() {return config.getIntProperty("timeout", 200);
}//example of getting config from injected value//the program needs to update the injected value when batch is changed in Apollo using @ApolloConfigChangeListener shown abovepublic int getBatch() {return this.batch;
}private static class JsonBean{private String someString;private int someInt;
}
}

在Configuration类中按照下面的方式使用:

@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestApolloAnnotationBean testApolloAnnotationBean() {
return new TestApolloAnnotationBean();
}
}

5.4.4 已有配置迁移

很多情况下,应用可能已经有不少配置了,比如Spring Boot的应用,就会有bootstrap.properties/yml, application.properties/yml等配置。

在应用接入Apollo之后,这些配置是可以非常方便的迁移到Apollo的,具体步骤如下:

  1. 在Apollo为应用新建项目

  2. 在应用中配置好META-INF/app.properties

  3. 建议把原先配置先转为properties格式,然后通过Apollo提供的文本编辑模式全部粘帖到应用的application namespace,发布配置

  • 如果原来格式是yml,可以使用YamlPropertiesFactoryBean.getObject转成properties格式

如果原来是yml,想继续使用yml来编辑配置,那么可以创建私有的application.yml namespace,把原来的配置全部粘贴进去,发布配置

  • 需要apollo-client是1.3.0及以上版本

把原先的配置文件如bootstrap.properties/yml, application.properties/yml从项目中删除

  • 如果需要保留本地配置文件,需要注意部分配置如server.port必须确保本地文件已经删除该配置项

如:

spring.application.name = reservation-service
server.port = 8080

logging.level = ERROR

eureka.client.serviceUrl.defaultZone = http://127.0.0.1:8761/eureka/
eureka.client.healthcheck.enabled = true
eureka.client.registerWithEureka = true
eureka.client.fetchRegistry = true
eureka.client.eurekaServiceUrlPollIntervalSeconds = 60

eureka.instance.preferIpAddress = true

六、 客户端设计

上图简要描述了Apollo客户端的实现原理:

  1. 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)

  2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。

  • 这是一个fallback机制,为了防止推送机制失效导致配置不更新

  • 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified

  • 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。

客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中

客户端会把从服务端获取到的配置在本地文件系统缓存一份

  • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置

应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知

七、 本地开发模式

Apollo客户端还支持本地开发模式,这个主要用于当开发环境无法连接Apollo服务器的时候,比如在邮轮、飞机上做相关功能开发。

在本地开发模式下,Apollo只会从本地文件读取配置信息,不会从Apollo服务器读取配置。

可以通过下面的步骤开启Apollo本地开发模式。

7.1 修改环境

修改/opt/settings/server.properties(Mac/Linux)或C:\opt\settings\server.properties(Windows)文件,设置env为Local:

env=Local

7.2 准备本地配置文件

在本地开发模式下,Apollo客户端会从本地读取文件,所以我们需要事先准备好配置文件。

7.2.1 本地配置目录

本地配置目录位于:

  • Mac/Linux: /opt/data/{appId}/config-cache

  • Windows: C:\opt\data{appId}\config-cache

appId就是应用的appId,如100004458。

请确保该目录存在,且应用程序对该目录有读权限。

【小技巧】 推荐的方式是先在普通模式下使用Apollo,这样Apollo会自动创建该目录并在目录下生成配置文件。

7.2.2 本地配置文件

本地配置文件需要按照一定的文件名格式放置于本地配置目录下,文件名格式如下:

*{appId}+{cluster}+{namespace}.properties*

  • appId就是应用自己的appId,如100004458

  • cluster就是应用使用的集群,一般在本地模式下没有做过配置的话,就是default

  • namespace就是应用使用的配置namespace,一般是application 

文件内容以properties格式存储,比如如果有两个key,一个是request.timeout,另一个是batch,那么文件内容就是如下格式:

request.timeout=2000
batch=2000

7.2.3 修改配置

在本地开发模式下,Apollo不会实时监测文件内容是否有变化,所以如果修改了配置,需要重启应用生效。

八、测试模式

1.1.0版本开始增加了apollo-mockserver,从而可以很好地支持单元测试时需要mock配置的场景,使用方法如下:

8.1 引入pom依赖

<dependency>
<groupId>com.ctrip.framework.apollogroupId>
<artifactId>apollo-mockserverartifactId>
<version>1.1.0version>
dependency>

8.2 在test的resources下放置mock的数据

文件名格式约定为mockdata-{namespace}.properties

8.3 写测试类

更多使用demo可以参考ApolloMockServerApiTest.java和ApolloMockServerSpringIntegrationTest.java。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
public class SpringIntegrationTest {
// 启动apollo的mockserver
@ClassRule
public static EmbeddedApollo embeddedApollo = new EmbeddedApollo();

@Test
@DirtiesContext // 这个注解很有必要,因为配置注入会弄脏应用上下文
public void testPropertyInject(){
assertEquals("value1", testBean.key1);
assertEquals("value2", testBean.key2);
}

@Test
@DirtiesContext
public void testListenerTriggeredByAdd() throws InterruptedException, ExecutionException, TimeoutException {
String otherNamespace = "othernamespace";
embeddedApollo.addOrModifyPropery(otherNamespace,"someKey","someValue");
ConfigChangeEvent changeEvent = testBean.futureData.get(5000, TimeUnit.MILLISECONDS);
assertEquals(otherNamespace, changeEvent.getNamespace());
assertEquals("someValue", changeEvent.getChange("someKey").getNewValue());
}

@EnableApolloConfig("application")
@Configuration
static class TestConfiguration{
@Bean
public TestBean testBean(){
return new TestBean();
}
}

static class TestBean{
@Value("${key1:default}")
String key1;
@Value("${key2:default}")
String key2;

SettableFuture futureData = SettableFuture.create();
@ApolloConfigChangeListener("othernamespace")private void onChange(ConfigChangeEvent changeEvent) {
futureData.set(changeEvent);
}
}
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值