5分钟学废携程出品配置中心阿波罗的原理与搭建
Posted 代码狂魔v
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5分钟学废携程出品配置中心阿波罗的原理与搭建相关的知识,希望对你有一定的参考价值。
目录
背景
- 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址……
- 对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制……
- 并且随着采用分布式的开发模式,项目之间的相互引用随着服务的不断增多,相互之间的调用复杂度成指数升高,每次投产或者上线新的项目时苦不堪言,因此需要引用配置中心治理。
在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。
目前已存在的配置中心
配置中心应运而生,目前配置中心有
- spring-cloud-config:spring出品,可以和spring cloud无缝配合
- 淘宝 diamond:已经不维护。
- disconf:java开发,蚂蚁金服技术专家发起,业界使用广泛。
- ctrip apollo:Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,具备规范的权限、流程治理等特性。
对比
为什么选择Apollo?下面是一个对比表
功能
几个配置中心在功能上的对比
|功能点
|
优先级
|
spring-cloud-config
|
ctrip apollo
|
disconf
|
备注
|
|
静态配置管理
|
高
|
基于file
|
支持
|
支持
| |
|
动态配置管理
|
高
|
支持
|
支持
|
支持
| |
|
统一管理
|
高
|
无,需要github
|
支持
|
支持
| |
|
多环境
|
中
|
无,需要github
|
支持
|
支持
| |
|
本地配置缓存
|
高
|
无
|
支持
|
支持
| |
|
配置锁
|
中
|
支持
|
不支持
|
不支持
|
不允许动态及远程更新
|
|
配置校验
|
中
|
无
|
无
|
无
|
如:ip地址校验,配置
|
|
配置生效时间
| |
重启生效,或手动refresh生效
|
实时
|
实时
|
需要结合热加载管理, springcloudconfig需要 git webhook+rabbitmq 实时生效
|
|
配置更新推送
|
高
|
需要手工触发
|
支持
|
支持
| |
|
配置定时拉取
|
高
|
无
|
支持
|
配置更新目前依赖事件驱动, client重启或者server端推送操作
| |
|
用户权限管理
|
中
|
无,需要github
|
支持
|
支持
|
现阶段可以人工处理
|
|
授权、审核、审计
|
中
|
无,需要github
|
支持
|
无
|
现阶段可以人工处理
|
|
配置版本管理
|
高
|
Git做版本管理
|
界面上直接提供发布历史和回滚按钮
|
操作记录有落数据库,但无查询接口
| |
|
配置合规检测
|
高
|
不支持
|
支持(但还需完善)
| | |
|
实例配置监控
|
高
|
需要结合springadmin
|
支持
|
支持,可以查看每个配置在哪些机器上加载
| |
|
灰度发布
|
中
|
不支持
|
支持
|
不支持部分更新
|
现阶段可以人工处理
|
|
告警通知
|
中
|
不支持
|
支持,邮件方式告警
|
支持,邮件方式告警
| |
|
依赖关系
|
高
|
不支持
|
不支持
|
不支持
|
配置与系统版本的依赖系统运行时的依赖关系
|
兼容性
几个配置中心和其他开发框架的对比
|功能点
|
优先级
|
spring-cloud-config
|
ctrip apollo
|
disconf
|
|
SpringBoot支持
|
高
|
原生支持
|
支持
|
与spring boot无相关
|
|
SpringCloud支持
|
高
|
原生支持
|
支持
|
与spring cloud无相关
|
|
客户端支持
|
低
|
Java
|
Java、.Net
|
java
|
|
业务系统侵入性
|
高
|
侵入性弱
|
侵入性弱
|
侵入性弱,支持注解及xml方式
|
|
依赖组件
|
高
|
Eureka
|
Eureka
|
zookeeper
|
可用性与易用性
| | | | | | |功能点
|
优先级
|
spring-cloud-config
|
ctrip apollo
|
disconf
|
|
单点故障(SPOF)
|
高
|
支持HA部署
|
支持HA部署
|
支持HA部署,高可用由zookeeper保证
|
|
多数据中心部署
|
高
|
支持
|
支持
|
支持
|
|
配置获取性能
|
高
|
unkown
|
unkown(官方说比spring快)
| |
|
配置界面
|
中
|
无,需要通过git操作
|
统一界面(ng编写)
|
统一界面
|
综上,ctrip applo是较好的选择方案,最终选择applo。
- 支持不同环境(开发、测试、生产)、不同集群
- 完善的管理系统,权限管理、发布审核、操作审计
- SpringBoot集成友好 ,较小的迁移成本
- 配置修改实时生效(热发布)
- 版本发布管理
设计
搭建之前,我们需要了解一下Apollo的设计思想,不至于搭建的时候像一个无头苍蝇
基本概念
既然定位是配置中心,那么直接作用的对象就是应用(Application),应用又可以在几个维度来观察
比如运行环境(Environment),开发、测试和生产不同环境的同一个应用的配置是不一样的
比如机房,或者叫做集群(Cluster),上海机房和北京机房的同一个应用配置也是不同的
比如配置的归类,某些配置是一些共性应用都需要的,可以集中管理起来,这叫做命名空间(Namespace)
说白了这些概念都是对应用的配置做隔离或者复用!
应用
- 这个很好理解,就是实际使用配置的应用,Apollo客户端在运行时需要知道当前应用是谁,从而可以去获取对应的配置
- 每个应用都需要有唯一的身份标识 - appId,我们认为应用身份是跟着代码走的,所以需要在代码中配置,具体信息请参见Java客户端使用指南。
环境
- 配置对应的环境,Apollo客户端在运行时需要知道当前应用处于哪个环境,从而可以去获取应用的配置
- 我们认为环境和代码无关,同一份代码部署在不同的环境就应该能够获取到不同环境的配置
- 所以环境默认是通过读取机器上的配置(server.properties中的env属性)指定的,不过为了开发方便,我们也支持运行时通过System Property等指定,具体信息请参见Java客户端使用指南。
集群
- 一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。
- 对不同的cluster,同一个配置可以有不一样的值,如zookeeper地址。
- 集群默认是通过读取机器上的配置(server.properties中的idc属性)指定的,不过也支持运行时通过System Property指定,具体信息请参见Java客户端使用指南。
命名空间
- 一个应用下不同配置的分组,可以简单地把namespace类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,rpc配置文件,应用自身的配置文件等
- 应用可以直接读取到公共组件的配置namespace,如DAL,RPC等
- 应用也可以通过继承公共组件的配置namespace来对公共组件的配置做调整,如DAL的初始数据库连接数
架构
V1
这是最简单的一个架构,Apollo 分为AdminService、Portal、ConfigService与Client
[图片上传失败…(image-cc9279-1621673497412)]
- ConfigService:既然叫配置中心,这个ConfigService就是核心,它和客户端交互,有配置变更就通过长连接把最新的配置推送给客户端,考虑的推送失败的情况,客户端默认每隔5分钟就会去配置中心拉取最新的配置(客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟),这就叫推拉结合,最大程度保证客户端的配置是最新的。
- AdminService:看名字大概能猜到一二,这是服务于管理员的,管理员在界面上操作各种配置,配置就会通过它写到ConfigDB里面,然后ConfigService通过每秒去轮询ConfigDB获取最新的配置推送给客户端,此处是一个典型的消费-生产场景,没有引入消息队列是为了尽量减少外部依赖!
- Portal:统一门户,就是管理员操作的前端界面,PortalDB用于保存Portal的用户权限角色等信息。
V2
V1版架构有一个问题,假设ConfigService挂了,那么客户端的配置就得不到更新,这个问题可以通过部署多个无状态的ConfigService来解决,但是引入了多个ConfigService服务发现就成为了一个新问题,客户端怎么才能知道当前有哪些ConfigService,它们的IP是多少?所以引入了注册中心Eureka!这样客户端就可以去Eureka获取服务列表!
[图片上传失败…(image-d52579-1621673497412)]
为啥选择Eureka?作者给了回答
为什么我们采用Eureka作为服务注册中心,而不是使用传统的zk、etcd呢?我大致总结了一下,有以下几方面的原因:
它提供了完整的Service Registry和Service Discovery实现首先是提供了完整的实现,并且也经受住了Netflix自己的生产环境考验,相对使用起来会比较省心。和Spring Cloud无缝集成我们的项目本身就使用了Spring Cloud和Spring Boot,同时Spring Cloud还有一套非常完善的开源代码来整合Eureka,所以使用起来非常方便。另外,Eureka还支持在我们应用自身的容器中启动,也就是说我们的应用启动完之后,既充当了Eureka的角色,同时也是服务的提供者。这样就极大的提高了服务的可用性。**这一点是我们选择Eureka而不是zk、etcd等的主要原因,为了提高配置中心的可用性和降低部署复杂度,我们需要尽可能地减少外部依赖。**Open Source最后一点是开源,由于代码是开源的,所以非常便于我们了解它的实现原理和排查问题。
V3
V2版引入了一个新问题,Eureka是只支持Java客户端的,那么.NET咋办?因为携程一些服务是.NET的,需要考虑了.NET的接入,所以增加了一个MetaServer的角色屏蔽掉,通过HTTP的方式获取服务列表,还可以增加一个网关用于负载均衡,这样只用访问网关就可以了,如下图
[图片上传失败…(image-c6011e-1621673497412)]
实际上,MetaServer和Eureka在Apollo中都集成在ConfigService中,跑在同一个JVM进程上,端口也是同一个,后面搭建的时候就需要关心到这一点!
搭建
采用docker搭建
数据库环境(5.6.5+)
docker run --name apl-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.24
查看下IP,此处是172.17.0.2
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' apl-mysql
以下操作是在容器内操作,登录MySQL,给数据库用户授权下
grant all privileges on *.* to root@"%" identified by "123456";
导入SQL
- ConfigDB:https://github.com/ctripcorp/apollo/blob/master/scripts/sql/apolloconfigdb.sql
- PortalDB:https://github.com/ctripcorp/apollo/blob/master/scripts/sql/apolloportaldb.sql
登录MySQL命令行,用source命令导入即可
Java环境
docker run -dit --name apl-java --privileged centos /usr/sbin/init
查看下IP,此处是172.17.0.3
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' apl-java
以下是在容器内操作,安装常用软件工具
yum install -y wget unzip
安装java环境
yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel which
cat > /etc/profile.d/java8.sh <<EOF
export JAVA_HOME=$(dirname $(dirname $(readlink $(readlink $(which javac)))))
export PATH=\\$PATH:\\$JAVA_HOME/bin
export CLASSPATH=.:\\$JAVA_HOME/jre/lib:\\$JAVA_HOME/lib:\\$JAVA_HOME/lib/tools.jar
EOF
source /etc/profile.d/java8.sh
去github发布页下载包:
https://github.com/ctripcorp/apollo/releases,当前最新版本是1.8.1,我们需要的文件为
- AdminService:apollo-adminservice-1.8.1-github.zip
- ConfigService:apollo-configservice-1.8.1-github.zip
- Portal:apollo-portal-1.8.1-github.zip
下载好解压到你喜欢的文件夹即可,然后开始配置数据库
配置ConfigService
- 配置数据库
vi config/application-github.properties
注意要把SSL关闭,否则可能连不上MySQL
spring.datasource.url = jdbc:mysql://172.17.0.2:3306/ApolloConfigDB?characterEncoding=utf8&useSSL=false
spring.datasource.username = root
spring.datasource.password = 123456
- 启动
启动ConfigService,执行命令脚本,主要要在解压后的当前目录下,其他几个也是
./scripts/startup.sh
启动日志文件在: /opt/logs/100003171/apollo-configservice.log,中间的数字可能不一样,以实际为准
启动成功后默认跑在8080端口,打开浏览器看一下是否能访问注册中心
提示:
由于是在容器里面,容器的端口不一定能被外部访问到,可以添加iptables DNAT规则
iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.3:8080
这句话的意思就是把172.17.0.3:8080端口和宿主机的8080端口映射起来,这样在外部才能访问,需要删除此条规则可以将-A换成-D即可
可以看到ConfigService已经注册好了
配置AdminService
- 配置数据库,和ConfigService配置文件一致
vi config/application-github.properties
- 启动
启动AdminService,执行命令脚本,主要要在解压后的当前目录下,其他几个也是
./scripts/startup.sh
启动成功后默认跑在8090端口,可以在Eureka看到
[图片上传失败…(image-37e5e1-1621673497411)]
配置Portal
- 配置数据库,和ConfigService配置文件一致
vi config/application-github.properties
配置环境
注意,Portal需要配置环境,文件位置在: config/apollo-env.properties,我们就配个开发环境,指向Eureka(上面解释过ConfigService和Eureka在一个JVM进程上),其他注释掉即可
#local.meta=http://localhost:8080
dev.meta=http://172.17.0.3:8080
#fat.meta=http://fill-in-fat-meta-server:8080
#uat.meta=http://fill-in-uat-meta-server:8080
#lpt.meta=${lpt_meta}
#pro.meta=http://fill-in-pro-meta-server:8080
这里解释下这个环境是什么意思,一个Portal可以管理多套环境,此处我们设置dev.meta标识这是开发环境。
环境的标识通过以下几种方式(针对客户端而言)
Environment可以通过以下3种方式的任意一个配置:
通过Java System Property可以通过Java的System Property env来指定环境在Java程序启动脚本中,可以指定-Denv=YOUR-ENVIRONMENT如果是运行jar文件,需要注意格式是java -Denv=YOUR-ENVIRONMENT -jar xxx.jar注意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支持以下几个值(大小写不敏感):
DEVDevelopment environmentFATFeature Acceptance Test environmentUATUser Acceptance Test environmentPROProduction environment
启动
启动AdminService,执行命令脚本,主要要在解压后的当前目录下,其他几个也是
./scripts/startup.sh
启动成功后默认跑在8070端口,同样访问不了指定下DNAT规则
iptables -t nat -A DOCKER -p tcp --dport 8070 -j DNAT --to-destination 172.17.0.3:8070
访问http://{虚拟机IP}:8070,默认登录用户名为apollo,密码为admin
客户端准备
此处以Java客户端为例,需要引入Apollo Client依赖(以Maven构建)
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.1.0</version>
</dependency>`
- 指定app.id,这是这个应用的唯一标识,不可重复
- 指定apollo.meta,指定获取元数据的地方,此处即为MetaServer:http://172.17.0.3:8080
这两个指定的配置文件为/META-INF/app.properties
一个最简单的Apollo客户端如下
[图片上传失败…(image-bf5cde-1621673497410)]
文末有代码清单
测试
部署项目
将项目打包并执行,注意设置环境为DEV
mkdir -p /opt/settings/
echo 'env=DEV' > /opt/settings/server.properties
然后访问一下
curl 'http://127.0.0.1:9000/apollo/getConfig'
值默认为default,下面我们通过Apollo,看这个值会不会动态改变
新增一个应用
登录Portal,新增一个应用,注意AppId要和配置的一样
点击提交后,进入刚才新建的应用,有一个默认的application的命名空间,然后点击右边新增配置,新增一个
[图片上传失败…(image-dbd4a8-1621673497410)]
点击提交后再点击发布
再访问一下
curl 'http://127.0.0.1:9000/apollo/getConfig'
如果返回的是测试变量说明动态更改成功!
再看看SpringBoot的日志
也打印出了相关提示
代码清单
ApolloController
@RestController
public class ApolloController {
//冒号后面的是默认值
@Value("${configValue:default}")
private String configValue;
@RequestMapping("/apollo/getConfig")
public String getConfig() {
return configValue;
}
}
SpringBootApolloClientApplication
@SpringBootApplication
//开启apollo配置
@EnableApolloConfig
public class SpringBootApolloClientApplication {
private static Logger logger = LoggerFactory.getLogger(SpringBootApolloClientApplication.class);
public static void main(String[] args) {
SpringApplication.run(SpringBootApolloClientApplication.class, args);
logger.info("=============================="+ SpringBootApolloClientApplication.class.getSimpleName()+" started==============================");
}
}
app.properties
# 应用的唯一标识,后面创建工程需要用到
app.id=apollo-demo
apollo.meta=http://172.17.0.3:8080
application.yml
server:
port: 9000
spring:
application:
name: springboot-apollo-client
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.scriptwang</groupId>
<artifactId>springboot-apollo-client</artifactId>
<version>1.0-SNAPSHOT</version>
<!--spring boot parent 最小依赖(parent)-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
</parent>
<dependencies>
<!--最小依赖(Spring MVC Tomcat等)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
参考
- https://www.cnblogs.com/xiaoqi/p/configserver-compair.html
- https://www.bookstack.cn/read/apollo-1.7-zh/cc8342e164e6c09c.md
- https://cloud.tencent.com/developer/article/1063232
- https://nobodyiam.com/2016/07/09/introduction-to-apollo/
- https://www.infoq.cn/article/ctrip-apollo-configuration-center-architecture
以上是关于5分钟学废携程出品配置中心阿波罗的原理与搭建的主要内容,如果未能解决你的问题,请参考以下文章
CentOS 7 搭建基于携程Apollo(阿波罗)配置中心单机模式