Apollo基本概念

一、简介
Apollo - A reliable configuration management system
Apollo的Github地址

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

Apollo包括服务端和客户端两部分:
1、服务端基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器。
2、Java客户端不依赖任何框架,能够运行于所有Java运行时环境,同时对Spring/Spring Boot环境也有较好的支持。

二、特性
基于配置的特殊性,所以Apollo从设计之初就立志于成为一个有治理能力的配置发布平台,目前提供了以下的特性:

1、统一管理不同环境、不同集群的配置
Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。同一份代码部署在不同的集群,可以有不同的配置,比如zookeeper的地址等。通过namespace可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖。

2、配置修改实时生效(热发布)
用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序。

3、版本发布管理
所有的配置发布都有版本概念,从而可以方便的支持配置的回滚。

4、灰度发布
支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有的应用实例。

5、权限管理、发布审核、操作审计
应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。所有的操作都有审计日志,可以方便的追踪问题。

6、客户端配置信息监控
可以在界面上方便的看到配置在被哪些实例使用

7、提供Java和.Net的原生客户端
①、提供Java和.Net的原生客户端,方便应用集成。
②、支持Spring Placeholder,Annotation和Spring Boot的ConfigurationProperties,方便应用使用(需要Spring 3.1.1+)。
③、同时提供了http接口,非Java和.Net应用也可以方便的使用。

8、提供开放平台API
Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。不过Apollo出于通用性考虑,不会对配置的修改做过多限制,只要符合基本的格式就能保存,不会针对不同的配置值进行针对性的校验,如数据库用户名、密码,Redis服务地址端口等。
对于这类应用配置,Apollo支持应用方便通过开放平台API在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制。

三、基础模型
在这里插入图片描述
1、用户在配置中心对配置进行修改并发布
2、配置中心通知Apollo客户端又配置更新
3、Apollo客户端从配置中心拉取最新的配置、更新本地的配置并通知到应用

四、Apollo的四个维度
Apollo基于四个维度去管理key-value格式的配置:

1、application(项目/应用) - 一级维度
①、Apollo客户端在运行时需要知道当前项目是谁,从而可以根据不同的应用来获取对应的项目的配置。
②、这个项目在Spring Boot代码里用app.id来标识,在VM options中用-Dapp.id来标识。

2、environment(环境) - 二级维度
实际开发中,不可能只有一个环境。常见的如:
①、DEV - 开发环境
②、FAT - 功能验收测试环境
③、UAT - 用户验收测试环境
④、PRO - 生产环境
⑤、其他环境(test - 测试环境、sit - 系统集成测试环境、pre - 灰度环境)

3、cluster(集群)- 三级维度
一个应用下不同实例的分组,比如上海、北京两个机房为两个集群,它们中某些参数配置可能不一致。

4、namespace(命名空间) - 四级维度
可以简单的把namespace类比为不同的配置文件,不同类型的配置存放在不同的文件中,如数据库配置文件、RPC配置文件、应用自身的配置文件等。

4.1、namespace的两种权限
①、public(公共的):public权限的namespace可以被任何应用获取。
②、private(私有的):只有被所属的应用获取到,一个应用尝试获取其他应用private的namespace,Apollo会报404异常。

4.2、namespace的三种类型
①、共有类型:具有public权限,游离与应用之外的配置,名称全局唯一。
②、私有类型:具有private权限。
③、关联类型(继承类型):具有private权限,可以将继承关联的namespace的配置,并且可以覆盖配置。

五、本地缓存
Apollo客户端会把从服务端获取到的配置在本地文件系统缓存一份,用于在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置,不影响应用正常运行。
本地缓存路径默认位以下路径,所以请确保/opt/data或C:\opt\data\目录存在,且应用有读写权限。

Mac/Linux:/opt/data/{appId}/config-cache
Windows:C:\opt\data\{appId}\config-cache

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

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

六、客户端设计
在这里插入图片描述
1、客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。
2、客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。
3、这是一个fallback机制,为了防止推送机制失效导致配置不更新。
4、客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified。
5、定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定apollo.refreshinterval来覆盖,单位为分钟。
6、客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中。
7、客户端会把从服务端获取到的配置在本地文件系统缓存一份,在遇到服务不可用,或者网络不通的时候,依然能从本地恢复配置。
8、应用程序从Apollo客户端获取最新的配置、订阅配置更新通知。

长连接是通过Http Long Polling实现的,具体而言:
1、客户端发起一个http请求到服务器
2、服务端会保持住这个连接60秒
3、如果在60秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应的namespace最新配置。
4、如果在60秒内没有客户端关心的配置变化,那么会返回http状态码304给客户端,客户端在收到服务端请求后会立即重新发起连接,回到第一步。
5、考虑到会有数万客户端向服务端发起长连,在服务端使用了async servlet(Spring DeferredResult)来服务Http Long Polling。

七、总体设计
在这里插入图片描述
从上往下看:
1、Config Service 提供配置的读取、推送等功能,服务对象是Apollo客户端。
2、Admin Service 提供配置的修改、发布等功能,服务对象是Apollo portal(管理界面)。
3、Config Service 和 Admin Service 都是多实例、无状态部署,所以需要将自己注册到Eureka中并保持心跳。
4、在Eureka之上,我们架了一层Meta Server用于封装Eureka的服务发现接口
5、Client通过域名访问Meta Server 获取 Config Service 服务列表(IP + Port),而后直接通过IP + Port访问服务,同时在Client侧会做load balance错误重试。
6、Portal通过域名访问Meta Server 获取 Admin Service 服务列表(IP + Port),而后直接通过IP + Port访问服务,同时在Portal侧会做load balance错误重试。
7、为了简化部署,我们实际上会把Config Service 、Eureka 和 Meta Server 三个逻辑角色部署在同一个JVM进程中。

八、可用性考虑
配置中心作为基础服务,可用性要求非常高,下面的表格描述了不同场景下Apollo的可用性:

场景影响降级原因
某台Config Service下线无影响Config Service无状态,客户端重连其他Config Service
所有Config Service下线客户端无法读取最新配置,Portal无影响客户端重启时,可以读取本地缓存配置文件
某台Admin Service下线无影响Admin Service无状态,Portal重连其它Admin Service
所有Admin Service下线客户端无影响,Portal无法更新配置
某台Portal下线无影响
全部Portal下线客户端无影响,Portal无法更新配置Portal域名通过slb绑定多台服务器,重试后指向可用的服务器
某个数据中心下线无影响多数据中心部署,数据完全同步,Meta Server/Portal 域名通过slb自动切换到其他存活的数据中心

Apollo部署

一、使用三个jar包部署

1、下载Apollo的三个jar包
Apollo三个jar包GitHub下载地址
在这里插入图片描述
2、将这三个jar包放在同一目录下

3、下载SQL脚本
Apollo依赖 MySQL 5.6.5+,需要两个数据库
在这里插入图片描述
SQL数据库脚本地址

4、启动Apollo
Apollo默认会启动3个服务,分别使用8070,8080,8090端口,请确保这3个端口当前没有被使用(可通过-Dserver.port=端口号 修改默认端口)。
通过cmd启动,以下启动命令基于 MySQL8.0

java -Xms256m -Xmx256m -Dspring.datasource.url=jdbc:mysql://localhost:3306/apolloconfigdb?serverTimezone=GMT -Dspring.datasource.username=root -Dspring.datasource.password=123456 -jar apollo-configservice-1.8.1.jar

java -Xms256m -Xmx256m -Dspring.datasource.url=jdbc:mysql://localhost:3306/apolloconfigdb?serverTimezone=GMT -Dspring.datasource.username=root -Dspring.datasource.password=123456 -jar apollo-adminservice-1.8.1.jar

java -Xms256m -Xmx256m -Ddev_meta=http://localhost:8080/ -Dserver.port=8070 -Dspring.datasource.url=jdbc:mysql://localhost:3306/apolloportaldb?serverTimezone=GMT -Dspring.datasource.username=root -Dspring.datasource.password=123456 -jar apollo-portal-1.8.1.jar

5、Apollo界面
三个启动完毕,通过localhost:8070进入管理页面,初始账号:apollo,初始密码:admin

二、通过Quick Start安装包
参考方式:Apollo Quick Start Build Scripts

使用Apollo

一、管理员工具
右上角的管理员工具

1、用户管理:可以新增用户
2、系统权限管理:可以赋予用户某些权限
3、开放平台授权管理:创建三方应用及赋权
4、系统参数:维护ApolloPortalDB.ServerConfig表数据,比如部门的修改(修改value值来新增、修改、删除部门)
5、删除应用、集群、AppNamespace:
6、系统信息:
7、配置导出:

在这里插入图片描述
二、项目管理 - 创建项目

部门:选择应用所在的部门
应用AppId:用来标识应用身份的唯一id,格式为String,需要和项目配置文件application.properties中配置的app.id对应
应用名称:应用名,仅用于界面展示
应用负责人:选择的人默认会成为该项目的管理员,具备项目权限管理、集群创建、namespace创建等权限

创建一个如下图所示的项目:
在这里插入图片描述
三、配置管理

1、发布配置
发布配置可以通过表格模式文本模式进行添加。
表格模式:单个key-value配置添加、修改。
在这里插入图片描述
文本模式:批量添加、修改,对于从已有的properties文件迁移尤其有用。
在这里插入图片描述
2、新增namespace
创建一个项目,默认会有一个application的namespace,namespace作为配置的分类,可当成一个配置文件,以添加rocketmq配置为例,添加spring-rocketmq的namespace配置rocketmq相关信息。
进入项目首页,点击左下角的【添加namespace】,共包括两项:关联公共namespace和创建namespace,选择【创建namespace】。

rocketmq.name-server = 127.0.0.1:9876
rocketmq.producer.group = PID_ACCOUNT

在这里插入图片描述
3、公共的namespace

在项目开发中,有一些配置可能是通用的,我们可以通过把这些通用的配置放到公共的namespace中,这样其他项目要使用时可以直接添加需要的namespace。

这里新建一个公共应用comment-template,并基于部门lcy_service创建springboot-http的namespace,公共namespace一定要是public的。

在这里插入图片描述
发布的配置内容如下:

spring.http.encoding.enabled=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.force=true
server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto
server.use-forward-headers=true
server.servlet.context-path=/

选择之前创建好的项目(account-service),添加namespace,选择关联公共namespace,同时可以覆盖公共配置里的配置项,然后发布即可。
在这里插入图片描述
四、集群配置

在有些情况下,应用有需求对不同的集群做不同的配置,比如部署在A机房的应用连接的rocketMQ服务器地址和部署在B机房的应用连接的rocketMQ服务器地址不一样。另外再项目开发过程中,也可为不同的开发人员创建不同的集群来满足开发人员的自定义配置。

1、创建集群
进入到account-service项目中,左边点击【添加集群】
在这里插入图片描述
2、同步集群配置

同步集群的配置是指在同一个应用中拷贝某个环境下的集群的配置到目标环境下的目标集群。

从其他集群同步已有配置到新集群,切换到原有集群(default),展开要同步的namespace,点击同步配置。
在这里插入图片描述
同步完之后,需要发布配置才生效。

Spring Boot 集成Apollo

一、引入依赖

<dependency>
	<groupId>com.ctrip.framework.apollo</groupId>
	<artifactId>apollo-client</artifactId>
    <version>1.8.0</version>
</dependency>

二、配置文件application.properties

server.port=8088
# 应用ID
app.id=account-service
# 是否开启Apollo
apollo.bootstrap.enabled=true
# 设置Namespace,默认application
apollo.bootstrap.namespaces=application,spring-rocketmq,lcy_service.spring-boot-http
# 指定使用哪个集群的配置
apollo.cluster=default
# Apollo服务器
apollo.meta=http://localhost:8080
# 为了防止配置中心无法连接等问题,Apollo可以通过该配置在本地缓存一份配置
# apllo.cacheDir=/opt/data/some-cache-dir
# Spring应用通常会使用 Placeholder 来注入配置,如${someKey:someDefaultValue},冒号前面的是 key,冒号后面的是默认值。
# 如果想关闭 placeholder 在运行时自动更新功能,可以设置为 false。
apollo.bootstrap.eagerLoad.enabled=false

三、代码获取配置
在Spring Boot启动类上加@EnableApolloConfig注解。
获取配置,通过@Value(${key})的方式注入,或者通过Config获取。

@RestController
public class ApolloController {
    @Value("${sms.enable}")
    private Boolean value;

    @GetMapping("/getApollo")
    public String getApollo(){
        String key = "rocket.producer.group";
        String namespace = "spring-rocketmq";
        Config config = ConfigService.getConfig(namespace);
        String rocketMq = config.getProperty(key,null);
        return rocketMq + "<----->" + value;
    }
}

在这里插入图片描述

其他环境部署
Apollo默认部署的是dev环境,这里再部署一个pro环境

在企业中常用的部署方案是:Apollo-admin service 和Apollo-config service两个服务分别在线上环境(pro),仿真环境(uat)和开发环境(dev)各部署一套,Apollo-portal作为管理端只部署一套,统一管理上述三套环境。

一、创建数据库
只需要创建apolloconfigdb,为了区分需要修改apolloconfigdb.sql里的数据库名字为apolloconfigdb_pro,然后执行sql文件。(PS:建议三个库都重新创建,即数据全部初始化)
在这里插入图片描述
二、启动configService和adminService - PRO环境
将pro环境的configService端口设置为8081,adminService设置为8091,启动命令:

java -Xms256m -Xmx256m -Dserver.port=8081 -Dspring.datasource.url=jdbc:mysql://localhost:3306/apolloconfigdb_pro?serverTimezone=GMT -Dspring.datasource.username=root -Dspring.datasource.password=123456 -jar apollo-configservice-1.8.1.jar

java -Xms256m -Xmx256m -Dserver.port=8091 -Dspring.datasource.url=jdbc:mysql://localhost:3306/apolloconfigdb_pro?serverTimezone=GMT -Dspring.datasource.username=root -Dspring.datasource.password=123456 -jar apollo-adminservice-1.8.1.jar

三、修改Eureka地址
更新pro环境apolloconfigdb_pro数据库serverconfig表里key为eureka.service.url的数据的value为http://localhost:8081/eureka/

四、调整ApolloPortal服务配置
服务配置项统一存储在apolloportaldb.serverconfig表中,可以通过管理员工具 - 系统参数页面进行配置:apollo.portal.envs - 可支持的环境列表(dev,pro)。
在这里插入图片描述
五、重新启动ApolloPortal
Apollo Portal需要在不同的环境访问不同的meta service(apollo-config service)地址,所以我们需要在配置中提供这些信息。

-Ddev_meta=http://localhost:8080/ -Dpro_meta=http://localhost:8081/

启动命令:

java -Xms256m -Xmx256m -Ddev_meta=http://localhost:8080/ -Dpro_meta=http://localhost:8081 -Dserver.port=8070 -Dspring.datasource.url=jdbc:mysql://localhost:3306/apolloportaldb?serverTimezone=GMT -Dspring.datasource.username=root -Dspring.datasource.password=123456 -jar apollo-portal-1.8.1.jar

六、Spring Boot启动

1、配置文件

server.port=8088
# 应用ID
app.id=account-service
# 是否开启Apollo
apollo.bootstrap.enabled=true
# 设置Namespace,默认application
apollo.bootstrap.namespaces=application,lcy.spring-rocketmq
# 指定使用哪个集群的配置
apollo.cluster=default
# 如果想关闭 placeholder 在运行时自动更新功能,可以设置为 false。
apollo.bootstrap.eagerLoad.enabled=false
# 为了防止配置中心无法连接等问题,Apollo可以通过该配置在本地缓存一份配置
apllo.cacheDir=/opt/data/some-cache-dir
# Spring应用通常会使用 Placeholder 来注入配置,如${someKey:someDefaultValue},冒号前面的是 key,冒号后面的是默认值。

2、添加配置文件
resource文件下创建apollo-env.properties指定不同环境的apollo地址。

dev.meta=http://localhost:8080
pro.meta=http://localhost:8081

3、JVM启动参数
JVM启动参数里需要配置环境。
在这里插入图片描述
4、启动项目即可
关于SpringBoot启动的说明
一般来说,Apollo的一些配置都写在application.properties配置文件里。
当然,也可以通过JVM参数来指定,详情如下:

# 项目名
-Dapp.id=account-service
# 指定环境,前提需要在resource下的apollo-env.properties指定了对应环境Apollo的地址。
-Denv=pro
# 指定Apollo的地址,与-Denv不要同时出现,即二者选其一
-Dapollo.meta=http://localhost:8080
# 指定缓存地址
-Dapollo.cacheDir=/opt/data/apollo-config
# 指定集群
-Dapollo.cluster=default

更多详细信息见官方文档

上文内容仅仅作为快速学习Apollo,更多内容见:Apollo官方文档

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐