Spring Cloud 系列之 Apollo 配置中心(一)
背景
随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址等等。
对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制等等。
在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。
Apollo 配置中心应运而生!Apollo - 一个可靠的配置管理系统。
Apollo 介绍
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。服务端基于 Spring Boot 和 Spring Cloud 开发,打包后可以直接运行,不需要额外安装 Tomcat 等应用容器。
Apollo 支持 4 个维度管理 Key-Value 格式的配置:
application (应用) environment (环境) cluster (集群) namespace (命名空间 Namespace 是配置项的集合,类似于一个配置文件的概念)
同时,Apollo 基于开源模式开发,开源地址:https://github.com/ctripcorp/apollo
官网文档:https://github.com/ctripcorp/apollo/wiki/Quick-Start
演示环境(Demo):
http://106.54.227.205/ 账号/密码:apollo/admin
上图是Apollo配置中心中一个项目的配置首页
在页面左上方的环境列表模块展示了所有的环境和集群,用户可以随时切换。 页面中央展示了两个namespace(application和FX.apollo)的配置信息,默认按照表格模式展示、编辑。用户也可以切换到文本模式,以文件形式查看、编辑。 页面上可以方便地进行发布、回滚、灰度、授权、查看更改历史和发布历史等操作。
Apollo 核心概念
「application (应用)」 这个很好理解,就是实际使用配置的应用,Apollo客户端在运行时需要知道当前应用是谁,从而可以去获取对应的配置 每个应用都需要有唯一的身份标识 -- appId,我们认为应用身份是跟着代码走的,所以需要在代码中配置,具体信息请参见Java客户端使用指南。
「environment (环境)」 配置对应的环境,Apollo客户端在运行时需要知道当前应用处于哪个环境,从而可以去获取应用的配置 我们认为环境和代码无关,同一份代码部署在不同的环境就应该能够获取到不同环境的配置 所以环境默认是通过读取机器上的配置(server.properties中的env属性)指定的,不过为了开发方便,我们也支持运行时通过System Property等指定,具体信息请参见Java客户端使用指南。
「cluster (集群)」 一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。 对不同的cluster,同一个配置可以有不一样的值,如zookeeper地址。 集群默认是通过读取机器上的配置(server.properties中的idc属性)指定的,不过也支持运行时通过System Property指定,具体信息请参见Java客户端使用指南。
「namespace (命名空间)」 一个应用下不同配置的分组,可以简单地把namespace类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,RPC配置文件,应用自身的配置文件等 应用可以直接读取到公共组件的配置namespace,如DAL,RPC等 应用也可以通过继承公共组件的配置namespace来对公共组件的配置做调整,如DAL的初始数据库连接数
Apollo 特性
「统一管理不同环境、不同集群的配置」 Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。 同一份代码部署在不同的集群,可以有不同的配置,比如zk的地址等 通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖 配置界面支持多语言(中文,English)
「配置修改实时生效(热发布)」 用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序。
「版本发布管理」 所有的配置发布都有版本概念,从而可以方便的支持配置的回滚。
「灰度发布」 支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例。
「权限管理、发布审核、操作审计」 应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。 所有的操作都有审计日志,可以方便的追踪问题。
「客户端配置信息监控」 可以方便的看到配置在被哪些实例使用
「提供Java和.Net原生客户端」 提供了Java和.Net的原生客户端,方便应用集成 支持Spring Placeholder,Annotation和Spring Boot的ConfigurationProperties,方便应用使用(需要Spring 3.1.1+) 同时提供了Http接口,非Java和.Net应用也可以方便的使用
「提供开放平台API」 Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。 不过Apollo出于通用性考虑,对配置的修改不会做过多限制,只要符合基本的格式就能够保存。 在我们的调研中发现,对于有些使用方,它们的配置可能会有比较复杂的格式,如xml, json,需要对格式做校验。 还有一些使用方如DAL,不仅有特定的格式,而且对输入的值也需要进行校验后方可保存,如检查数据库、用户名和密码是否匹配。 对于这类应用,Apollo支持应用方通过开放接口在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制
「部署简单」 配置中心作为基础服务,可用性要求非常高,这就要求Apollo对外部依赖尽可能地少 目前唯一的外部依赖是MySQL,所以部署非常简单,只要安装好Java和MySQL就可以让Apollo跑起来 Apollo还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数
Apollo 总体设计
官方文档:https://github.com/ctripcorp/apollo/wiki/Apollo配置中心设计
架构模块
上图简要描述了 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进程中
1.3 各模块概要介绍
1.3.1 Config Service
提供配置获取接口 提供配置更新推送接口(基于Http long polling) 服务端使用Spring DeferredResult实现异步化,从而大大增加长连接数量 目前使用的tomcat embed默认配置是最多10000个连接(可以调整),使用了4C8G的虚拟机实测可以支撑10000个连接,所以满足需求(一个应用实例只会发起一个长连接)。
接口服务对象为Apollo客户端
1.3.2 Admin Service
提供配置管理接口 提供配置修改、发布等接口 接口服务对象为Portal
1.3.3 Meta Server
Portal通过域名访问Meta Server获取Admin Service服务列表(IP+Port) Client通过域名访问Meta Server获取Config Service服务列表(IP+Port) Meta Server从Eureka获取Config Service和Admin Service的服务信息,相当于是一个Eureka Client 增设一个Meta Server的角色主要是为了封装服务发现的细节,对Portal和Client而言,永远通过一个Http接口获取Admin Service和Config Service的服务信息,而不需要关心背后实际的服务注册和发现组件 Meta Server只是一个逻辑角色,在部署时和Config Service是在一个JVM进程中的,所以IP、端口和Config Service一致
1.3.4 Eureka
基于Eureka和Spring Cloud Netflix提供服务注册和发现 Config Service和Admin Service会向Eureka注册服务,并保持心跳 为了简单起见,目前Eureka在部署时和Config Service是在一个JVM进程中的(通过Spring Cloud Netflix)
1.3.5 Portal
提供Web界面供用户管理配置 通过Meta Server获取Admin Service服务列表(IP+Port),通过IP+Port访问服务 在Portal侧做load balance、错误重试
1.3.6 Client
Apollo提供的客户端程序,为应用提供配置获取、实时更新等功能 通过Meta Server获取Config Service服务列表(IP+Port),通过IP+Port访问服务 在Client侧做load balance、错误重试
服务端
上图简要描述了配置发布的大致过程:
用户在Portal操作配置发布 Portal调用Admin Service的接口操作发布 Admin Service发布配置后,发送ReleaseMessage给各个Config Service Config Service收到ReleaseMessage后,通知对应的客户端
客户端
上图简要描述了Apollo客户端的实现原理:
客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现) 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。 这是一个fallback机制,为了防止推送机制失效导致配置不更新 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval
来覆盖,单位为分钟。
客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中 客户端会把从服务端获取到的配置在本地文件系统缓存一份 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知
环境准备
点击链接观看:Apollo 搭建服务端视频(获取更多请关注公众号「哈喽沃德先生」)
Java
Apollo 服务端:1.8+ Apollo 客户端:1.7+
由于需要同时启动服务端和客户端,所以建议安装Java 1.8+。
MySQL
版本要求:5.6.5+
Apollo的表结构对timestamp
使用了多个default声明,所以需要5.6.5以上版本。
下载Quick Start安装包
Apollo 给我们准备好了一个Quick Start安装包,大家只需要下载到本地,就可以直接使用,免去了编译、打包过程。
安装包共50M,如果访问github网速不给力的话,可以从百度网盘下载。
从Github下载 checkout或下载apollo-build-scripts项目 由于Quick Start项目比较大,所以放在了另外的repository,请注意项目地址 https://github.com/nobodyiam/apollo-build-scripts
从百度网盘下载 通过https://github.com/ctripcorp/apollo/wiki/Quick-Start#13-下载quick-start安装包页面的网盘链接下载 下载到本地后,在本地解压apollo-quick-start.zip
为啥安装包要58M这么大? 因为这是一个可以自启动的jar包,里面包含了所有依赖jar包以及一个内置的tomcat容器
安装 Apollo
创建数据库
Apollo 服务端共需要两个数据库:ApolloPortalDB
和ApolloConfigDB
,我们把数据库、表的创建和样例数据都分别准备了 sql 文件,只需要导入数据库即可。
❝
注意:如果你本地已经创建过Apollo数据库,请注意备份数据。我们准备的sql文件会清空Apollo相关的表。
❞
创建 ApolloPortalDB 数据库
通过各种MySQL客户端导入sql/apolloportaldb.sql即可。
创建 ApolloConfigDB 数据库
通过各种MySQL客户端导入sql/apolloconfigdb.sql即可。
配置数据库连接信息
Apollo 服务端需要知道如何连接到你前面创建的数据库,所以需要编辑demo.sh,修改 ApolloPortalDB 和 ApolloConfigDB 相关的数据库连接串信息。
❝
注意:填入的用户需要具备对 ApolloPortalDB 和 ApolloConfigDB 数据的读写权限。
❞
#apollo config db info
apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
apollo_config_db_username=用户名
apollo_config_db_password=密码(如果没有密码,留空即可)
apollo portal db info
apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8
apollo_portal_db_username=用户名
apollo_portal_db_password=密码(如果没有密码,留空即可)
❝
注意:不要修改 demo.sh 的其它部分
❞
搭建服务端
确保端口未被占用
Quick Start脚本会在本地启动3个服务,分别使用8070, 8080, 8090端口,请确保这3个端口当前没有被使用。
执行启动脚本
./demo.sh start
Apollo 提供的脚本文件为 .sh
文件,如果你的安装环境是在 Linux 系统下直接运行以上命令即可,如果你想在 Windows 环境下运行该脚本,先安装 Git 然后在 demo.sh
所在目录下鼠标右键点击 Git Bash Here
,然后再通过以上命令运行脚本即可。
当看到如下输出后,就说明启动成功了!
==== starting service ====
Service logging file is ./service/apollo-service.log
Started [10768]
Waiting for config service startup.......
Config service started. You may visit http://localhost:8080 for service status now!
Waiting for admin service startup....
Admin service started
==== starting portal ====
Portal logging file is ./portal/apollo-portal.log
Started [10846]
Waiting for portal startup......
Portal started. You can visit http://localhost:8070 now!
异常排查
如果启动遇到了异常,可以分别查看 service 和 portal 目录下的 log 文件排查问题。
❝
注:在启动 apollo-configservice 的过程中会在日志中输出 eureka 注册失败的信息,如
com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused
。需要注意的是,这个是预期的情况,因为 apollo-configservice 需要向 Meta Server(它自己)注册服务,但是因为在启动过程中,自己还没起来,所以会报这个错。后面会进行重试的动作,所以等自己服务起来后就会注册正常了。❞
访问
访问:http://localhost:8070/ Quick Start 集成了 Spring Security,输入用户名 apollo,密码 admin 后登录。
登录成功后,首页如下,Apollo 还提供了一个 SampleApp
样本案例供我们学习使用。
创建项目
点击对应按钮创建项目。
这里先通过默认的样例部门演示(后面我会讲如何添加部门),AppId 对应客户端配置文件中 app.id。
创建成功如下图。
客户端接入服务端
点击链接观看:Apollo 客户端接入服务端视频(获取更多请关注公众号「哈喽沃德先生」)
下面通过最常用、便捷的方式,即基于 Spring Boot 的集成方式来接入服务端。
apollo-demo
聚合工程。Spring Boot 2.2.4.RELEASE
order-service
:订单服务,端口9090
order-service02
:订单服务,端口9091
添加依赖
<!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-client -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.6.0</version>
</dependency>
配置文件
order-service
和 order-service02
的配置信息除端口外一致。
server:
port: 9090 # 端口
spring:
application:
name: order-service # 应用名称
# apollo 相关配置
app:
id: order-service # 与 Apollo 配置中心中的 AppId 一致
apollo:
meta: http://localhost:8080 # Apollo 中的 Eureka 注册中心地址
#cluster: # 指定 Apollo 集群,相同集群实例使用对应集群的配置
#cacheDir: # 配置缓存目录,网络不可用时任然可提供配置服务
bootstrap:
enable: true # 启用 apollo
env: DEV # 指定环境
# 自定义配置
name: order-service-dev
mysql:
host: localhost
port: 3306
username: root
password: root
配置文件实体类
order-service
和 order-service02
的配置文件实体类代码一致。
package com.example.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ConfigProperties {
@Value("${name}")
private String name;
@Value("${mysql.host}")
private String mysqlHost;
@Value("${mysql.port}")
private Integer mysqlPort;
@Value("${mysql.username}")
private String mysqlUsername;
@Value("${mysql.password}")
private String mysqlPassword;
}
控制层
order-service
和 order-service02
的控制层代码一致。
package com.example.controller;
import com.example.config.ConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class ConfigController {
@Autowired
private ConfigProperties configProperties;
@Value("${name}")
private String name;
@GetMapping("/name")
public String getName() {
return configProperties.getName();
}
@GetMapping("/mysql")
public Map<Object, Object> getMySQLProperties() {
// JDK9中的新特性,快速创建只读集合。
return Map.of("host", configProperties.getMysqlHost(),
"port", configProperties.getMysqlPort(),
"username", configProperties.getMysqlUsername(),
"password", configProperties.getMysqlPassword());
}
}
启动类
启动类需要添加 @EnableApolloConfig
注解。
order-service
和 order-service02
的启动类代码一致。
package com.example;
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableApolloConfig
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
测试
修改配置信息前
访问:http://localhost:9090/name 和 http://localhost:9091/name 结果如下:
访问:http://localhost:9090/mysql 和 http://localhost:9091/mysql 结果如下:
新增配置信息
进入项目后点击右上角的 新增配置
。
添加配置项 name
、mysql.username
、mysql.password
。
发布配置信息
将刚才添加的配置信息批量发布至应用。
修改配置信息后
控制台打印信息如下:
c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: order-service-dev-2.0, key: name, beanName: configController, field: com.example.controller.ConfigController.name
c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: root123, key: mysql.password, beanName: configProperties, field: com.example.config.ConfigProperties.mysqlPassword
c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: root123, key: mysql.username, beanName: configProperties, field: com.example.config.ConfigProperties.mysqlUsername
访问:http://localhost:9090/name 和 http://localhost:9091/name 结果如下:
访问:http://localhost:9090/mysql 和 http://localhost:9091/mysql 结果如下:
❝
以上只是 Apollo 的入门教程,后面我们会学习 Apollo 的更多高级玩法,比如多环境部署,高可用环境搭建等等。
下一篇我们讲解 Apollo 部门管理、用户管理、配置管理、集群管理,记得关注噢~
❞
本文采用 知识共享「署名-非商业性使用-禁止演绎 4.0 国际」许可协议
。
大家可以通过 分类
查看更多关于 Spring Cloud
的文章。
Spring Cloud 系列之 Apollo 配置中心(一)的更多相关文章
- Spring Cloud 系列之 Apollo 配置中心(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Apollo 配置中心(一) 本篇文章讲解 Apollo 部门管理.用户管理.配置管理.集群管理. 点击链接观看:Ap ...
- Spring Cloud 系列之 Apollo 配置中心(三)
本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Apollo 配置中心(一) Spring Cloud 系列之 Apollo 配置中心(二) 本篇文章讲解 Apol ...
- Spring Cloud 系列之 Apollo 配置中心(四)
本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Apollo 配置中心(一) Spring Cloud 系列之 Apollo 配置中心(二) Spring Clou ...
- Spring Cloud 系列之 Config 配置中心(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Config 配置中心(一) 本篇文章讲解 Config 如何实现配置中心自动刷新. 配置中心自动刷新 点击链接观看: ...
- Spring Cloud 系列之 Config 配置中心(三)
本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Config 配置中心(一) Spring Cloud 系列之 Config 配置中心(二) 本篇文章讲解 Conf ...
- Spring Cloud 系列之 Consul 配置中心
前面我们已经学习过 Spring Cloud Config 了: Spring Cloud 系列之 Config 配置中心(一) Spring Cloud 系列之 Config 配置中心(二) Spr ...
- Spring Cloud 系列之 Config 配置中心(一)
服务配置现状 配置文件是我们再熟悉不过的,在微服务系统中,每个微服务不仅仅只有代码,还需要连接其他资源,例如数据库的配置或功能性的开关 MySQL.Redis .Security 等相关的配置.除了项 ...
- Spring Cloud 入门教程 - 搭建配置中心服务
简介 Spring Cloud 提供了一个部署微服务的平台,包括了微服务中常见的组件:配置中心服务, API网关,断路器,服务注册与发现,分布式追溯,OAuth2,消费者驱动合约等.我们不必先知道每个 ...
- Spring Boot + Spring Cloud 实现权限管理系统 配置中心(Config、Bus)
技术背景 如今微服务架构盛行,在分布式系统中,项目日益庞大,子项目日益增多,每个项目都散落着各种配置文件,且随着服务的增加而不断增多.此时,往往某一个基础服务信息变更,都会导致一系列服务的更新和重启, ...
随机推荐
- P1353 Running S
题意:https://www.luogu.com.cn/problem/P1353 奶牛们打算通过锻炼来培养自己的运动细胞,作为其中的一员,贝茜选择的运动方式是每天进行 n 分钟的晨跑.在每分钟的开始 ...
- Java变量相关
1.Java是强类型语言 所有的变量必须先声明,后使用: 指定类型后只能接受类型匹配的值: 2.变量声明 变量标识符由字母.数字.下划线和$组成: 关键字和保留字不能做标识符: 长度不限制: 大小写区 ...
- CSS躬行记(10)——CSS方法论
方法论是一个哲学术语,会对一系列具体的方法进行分析研究.系统总结并最终提出较为一般性的原则.CSS方法论是一种面向CSS.由个人和组织设计.已被诸多项目检验且公认有效的最佳实践.这些方法论都会涉及结构 ...
- 【Kafka】Kafka简单介绍
目录 基本介绍 概述 优点 主要应用场景 Kafka的架构 四大核心API 架构内部细节 基本介绍 概述 Kafka官网网站:http://kafka.apache.org/ Kafka是由Apach ...
- PROTEUS串口仿真遇到的BUG(转载)
转载自:http://blog.csdn.net/viperchaos/article/details/6246419 串口通信设置的顺序非常重要,最好严格按照步骤来,在开启数据接受的使能之前最好一定 ...
- [hdu1085]生成函数
题意:给a个1.b个2.c个5,求不能构成最小的数 思路: 先求1能构成的所有数,2能构成的所有数,5能构成的所有数,它们的方法数显然都是1,现在考虑把3者结合在一起,由于结果为和的形式,而又是循环加 ...
- python 基础应用4
1.列表所有元素全部单独输出 #所有元素全部单独输出 li = [1,2,3,'taibai',[4,5,6,'taibaia']] for i in li: if type(i) == list: ...
- 网站设计时应考虑哪些因素,以保证网站是对SEO友好
根据用户的搜索习惯做好栏目的设计 根据用户的习惯做好三大标签的设计 做好首页栏目的展现布局 对于用户来说的重点 展示栏目的合理化 多样化 细节化 代码的静态化 域名 服务器购买稳定 合格 网站内容的 ...
- 【雕爷学编程】Arduino动手做(60)---WS2812直条8位模块
37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的.鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为 ...
- 详解vue生命周期及每个阶段适合进行的操作
VUE生命周期的四个阶段 create 创建 -------- 创建vue实例并初始化 mount 挂载 -------- 把vue实例和视图进行关联 update 更新 ------- 监听数据与视 ...