一.为什么需要配置中心?
由于程序日益复杂,相应的配置也越来越多,对配置的期望也会变高(比如实时性,分环境管理),因此我们需要一个配置中心去管理我们的配置。
二.Apollo是什么?
Apollo是携程框架部门研发的开源配置管理中心,能够集中管理应用在不同环境、不同集群的配置,配置修改后能够实时的推送到应用端,并且有关于权限管理、流程治理等功能。
(一)Apollo支持四个维度管理key-value格式的配置
- application(应用级别的,针对于当前应用)
- environment(环境级别的,在不同环境下可以有不同的配置。比如dev、prod环境)
- cluster(集群。可以根据集群分为不同的配置)
- namespace(命名空间。不同的配置文件,比如db的配置,rpc的配置等等)
(二)Apollo的特性
- 可以统一去管理不同环境、不同集群的配置。
(1)同一份代码部署在不同的集群,可以有不同的配置。
(2)可以通过配置namespace去让不同的应用共享同一份配置(public公共配置),也可以通过关联公共的namespace,并且根据自己的需求对公共配置进行覆盖。(相当于子类可以继承父类,对于父类中的成员,不满足需要的可以自己进行覆盖。) - 支持热发布。在管理界面修改完配置后,客户端可以实时的接收到。(据它的描述,时间为1s)
- 每一次改动配置进行发布,都会有对应的版本的概念,方便后续进行回滚。
- 灰度发布。(是指改动配置点击发布,只针对部分实例生效。待观察之后,没有问题,再推送到所有实例。)
- 权限管理(可以针对不同的操作,分配以不同的权限。并且在配置的改动发布上,分为编辑和发布两个独立的操作。)
- 支持Java和.Net客户端。
- 提供开放平台API。
- 部署简单方便(目前唯一的外部依赖是MySQL,因此安装好JDK和MySQL就可以运行。)
(三)Apollo的核心概念
- application(应用):实际使用配置的应用。
- environment(环境):配置所对应的环境。比如dev、prd等环境,在不同的环境中可以有不同的配置。默认是读取机器上的配置(server.properties中的env属性)
- cluster(集群):一个应用下不同实例的分组。比如将北京机房的应用实例分为一个集群,燕郊机房的应用实例分为另一个集群。同一个配置在不同的集群下可以有不同的值。默认是读取机器上(server.properties中的idc属性)
- namespace(命名空间):一个应用下不同配置的分组,可以理解为配置文件。比如数据库配置文件,rpc配置文件,以及应用自身的配置文件。
(四)Apollo客户端的实现原理
- 客户端和服务端通过http long polling保持了一个长连接,从而能第一时间获取配置更新的推送。
- 客户端会定时从Apollo配置中心服务端拉取应用的最新配置
- 客户端获取到最新的配置后,会保存在内存中。
- 客户端会将获取到的配置缓存一份在本地(为了保证服务不可用时,从本地恢复)
- 应用程序可以通过客户端取获取最新的配置。
- 注:想深入了解的可以去研究下源码,在github上同时也给出了Apollo的源码分析链接)
(五)API的使用方式
ConfigService.getConfigFile(String namespace,ConfigFileFormat configFileFormat) //对于非properties格式的namespace
Config config = ConfigService.getAppConfig();//获取默认的application namespace的配置
Config config = ConfigService.getConfig(“namesapce的名称");//获取非application namespace的配置
(六)Apollo的部署
- 准备工作(要部署到那台机器上的环境)
(1)Java环境:JDK1.8
(2)MySQL:由于作者提到apollo的表结构对timestamp使用了多个default声明,因此需要5.6.5以上版本。
(3)如果是将打包编译工作在部署机器上操作,则需要安装maven(version3.5以上),否则不需要。
- 步骤
(1)创建数据库。apollo服务端需要两个库,分别是ApolloPortalDB和ApolloConfigDB。命令行登录myql,执行source /你的sql文件存放的路径/sql/apolloportaldb.sql和apolloconfigdb.sql,将apollo提供的库表文件导入到mysql 中。
(2)如果希望portal管理多套环境,首先需要在ApolloPortalDB的人ServerConfig表中,更改apollo.portal.envs行的value列,多个之间以逗号分开(大小写均可)。如下图所示
(3)在ApolloConfigDB的ServerConfig表中,更改eureka地址。比如:http://10.0.1.157:9002/eureka/(后缀要注意为/eureka/)其实就是和meta_server地址保持一致。这里的meta server只是个逻辑角色,是对eureka的一层封装。不同的环境对应自己的一套adminService,configService以及configdb的环境,自然这里的eurela地址也会不同。在实际部署时需要注意。
(5)需要将apollo-client打包上传到公司的maven私服中去。将build.sh中的mvn clean install -DskipTests -pl apollo-client -am $META_SERVERS_OPTS这一行的install改为deploy。注意修改自己maven的setting文件
<servers>
<server>
<id>releases</id>
<username>someUserName</username>
<password>somePassword</password>
</server>
<server>
<id>snapshots</id>
<username>someUserName</username>
<password>somePassword</password>
</server>
</servers>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<releases.repo>http://${your_nexus_url}/nexus/content/repositories/${release-repository}</releases.repo>
<snapshots.repo>http://${your_nexus_url}/nexus/content/repositories/${snapshotrepository}</snapshots.repo>
</properties>
</profile>
</profiles>
(6)执行编译打包。
①确保数据库和meta server地址在build.sh文件中都已经配置好的话,就可以打包编译了。
②命令:./build.sh。此脚本会依次打包apollo-configservice apollo-adminservice Apollo-portal apollo-client部署apollo-configservice
③将apollo-configservice/target下打出来的后缀为-github.zip的包,上传到要部署的机器上。Mac可使用scp命令,Windows可使用Xshell等第三方工具。上传成功后使用unzip命令解压,启动和停止服务的脚本分别是scripts下的start.sh和shutdown.sh。
④部署adminservice和portal也是如此,不一一赘述了。(需要提到的一点是,三个服务默认的端口分别是adminservice:8090,portal:8080,configservice:8080。为了防止冲突,我将三个端口分别改为了adminservice:9001,configservice:9002,portal:9003。在各个服务的start.sh中server_port中)
⑤这里要注意:如果是想使用不同的环境,那么每个环境需要独立的部署一套adminService,configService和configdb。对应的,在启动的bulid.sh脚本中,注意填写不同环境的meta_server地址,因为需要去获取服务。像我之前这种写法,不同的环境指向的都是同一个meta_server地址(这里是dev环境),就会出现虽然portal界面能显示不同的环境,但是在创建集群时,就会出现集群共享的问题,也就是说本来应该在dev环境下才应该显示的集群,会出现在所有集群下。(原因在于不同环境的meta_server地址是相同的)。我在测试的时候,只使用了两套环境:dev和pro。其中pro环境的adminServicee,configService部署在和dev环境同一台机器上(改了不同的端口号,相当于启了两个进程),其中的configdb连的是我本机的(因为我看了下mysql如果要启动两个实例,好像不是仅仅改端口号,为了省事,我就用了本机的mysql了。)
三.已有应用接入Apollo步骤
- 在Apollo的配置界面创建新项目,填入选项中的内容。其中的应用Id对应已有的应用程序src/main/resources/META-INF下的app.properties文件中的key(app.id=xxx,String类型)
app.id=123456
- 在resources目录下,新增appllo-env.properties,配置各个环境的服务器地址。
local.meta=http://127.0.0.1:8080 dev.meta=http://127.0.0.1:8080 fat.meta=${fat_meta} uat.meta=${uat_meta} lpt.meta=${lpt_meta} pro.meta=${pro_meta}
Mac或者Linux下,在/opt/settings/server.properties(如果没有,则新建)文件下,设置env=DEV(指定环境)。(Windows下在C:\opt\settings\server.properties)
运行SimpleApolloConfigDemo,在控制台输入key,看是否能够读取到最新发布的配置中的value。
- 上传至公司maven私服后,即可按照如下方式使用。
<!--apollo client --> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>0.11.0-SNAPSHOT</version> </dependency>
四.Apollo配置中心的使用
- 配置中心的使用,可以自己实际操作一遍,很多功能自己试一试就清楚了。这里主要说一下namespace的格式的问题,每个人实际情况可能各不相同,还是要根据自己的需求来决定使用什么格式的文件。
- 目前的namespace支持格式:properties、json、xml、yml、yaml
- properties格式(key=value)
username=root
password=root
- json格式
{
"birthday": "1997-08-09",
"major": ["敲代码", "打篮球"],
"school": "家里蹲",
"car": null,
"name": "祖传码农",
"has_girlfriend": true,
"house": null,
"age": 20
}
- yml和yaml格式
#大小写敏感
#使用缩进来表示层级关系(使用空格)
#相同层级的元素左侧对齐
##表示注释
#使用冒号表示映射关系
#使用 - 表示数组。
#~表示null
#示例:
server:
admin:
port:8080
serviceId:
- "xxx"
- "xxx"
- xml格式
<?xml version="1.0" encoding="utf-8"?>
<softCompany>
<company>MicroSoft</company>
<company>google</company>
<company>Apple</company>
</softCompany>