tags:
- Apollo
- Spring Boot
- 快速使用
- 框架整合
- 后台资料
Ⅰ简介
一、什么是配置中心
-
什么是配置
- 应用程序在启动和运行的时候往往要读取一些配置信息,配置基本上都伴随着应用程序的整个生命周期,比如:数据库连接参数、启动参数等;
- 配置主要有以下几个特点:
- 配置是独立于程序的只读变量
- 配置首先是独立于程序的,同一份程序在不同的配置下会有不同的行为;
- 其次,配置对程序是只读的,程序通过读取配置来改变自己的行为,但是程序不应该去改变配置;
- 配置伴随应用的整个生命周期
- 配置贯穿于应用的整个生命周期,应用在启动时通过读取配置来初始化,在运行时根据配置调整行为。比如:启动时徐奥读取服务器的端口号、系统在运行过程中需要读取定时策略执行定时任务等;
- 配置可以有多种加载方式
- 常见的有程序内部硬编码、配置文件、环境变量、启动参数、基于数据库等;
- 配置需要治理
- 权限控制:由于配置能改变程序的行为,不正确的配置甚至引起灾难,所以对配置的修改必须有比较完善的权限控制;
- 不同环境、集群配置管理:同一份程序在不同的环境(开发、测试、生产)、不同集群(如不同的数据中心)经常需要由不同的配置,所以需要有完善的环境、集群配置管理;
- 配置是独立于程序的只读变量
-
什么是配置中心
-
传统单体应用程序存在一些潜在缺陷,如随着规模的扩大,部署效率降低、团队协作效率差、系统可靠性变差、维护困难、新功能上线周期长等;所以迫切需要一种新的架构去解决这些问题,而微服务(microsevices)架构正是当下的一种流行的解决办法;
-
不过解决一个问题的同时,往往会诞生出很多新的问题,所以微服务化的过程中伴随着很多的挑战,其中一个挑战就是有关服务(应用)配置的;当系统从一个单体应用,被拆分成分布式系统上的一个个服务节点后,配置文件也必须跟着迁移(分割),这样配置就分散了,不仅如此,分散中还包含着冗余,如下图:
-
配置中心将配置从应用中剥离出来,统一管理,优雅的解决了配置的动态变更、持久化、运维成本等问题;
-
应用自身既不需要去添加管理配置接口,也不需要自己去实现配置的持久化,更不需要引入 “定时任务” 以免降低运行部署效率;
-
总的来说,配置中心就是一种统一管理各种应用程序配置基础服务组件
-
集中管理配置,那么就要将应用的配置作为一个单独的服务抽离出来了,同理也需要解决新的问题,比如:版本管理(为了支持回滚),权限管理等;
-
总结一下,在传统巨型单体应用纷纷转向细粒度微服务架构的历史进程中,配置中心是微服务化不可缺少的一个系统组件,在这种背景下中心化的配置服务即配置中心应运而生,一个合格的配置中心需要满足:
- 配置项容易读取和修改
- 添加新项配置简单直接
- 支持对配置的修改的检视已把控风险
- 可以查看配置修改的历史记录
- 不同部署环境支持隔离
-
二、什么是 Apollo
- Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用的不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景;
- Apollo 包括服务端和客户端两个部分:
- 服务端基于 Spring Boot 和 Spring Cloud 开发,打包后可以直接运行,不需要额外的安装 Tomcat 等应用容器;
- Java 客户端不依赖任何框架,能够运行于所有 Java 运行时环境,同时对 Spring / Spring Boot 环境也有较好的支持;
三、Apollo 特性
- 基于配置的特殊性,所以 Apollo 从设计之初就立志于成为一个有治理能力的配置发布平台,目前提供了以下特性:
- 统一管理不同环境、不同集群的配置
- Apollo 提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置;
- 同一份代码部署在不同的集群,可以有不同的配置,比如 zookeeper 的地址等;
- 通过命名空间(namespace)可以很方便地支持多个不同应用共享同一份配置,同时还允许应用对共享地配置进行覆盖;
- 配置修改实时生效(热发布)
- 用户在 Apollo 修改完配置并发布后,客户端能实时(1s)接收到最新的配置,并通知到应用程序;
- 版本发布管理
- 所有的配置发布都有版本概念,从而可以方便地支持配置的回滚;
- 灰度发布
- 支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推送给所有应用实例;
- 权限管理、发布审核、操作审计
- 应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误;
- 所有的操作都有审计日志,可以方便的追踪问题;
- 客户端配置信息监控
- 可以在界面上方便地看到配置在被哪些实例使用;
- 提供 Java 和 .Net 原生客户端
- 提供了 Java 和 .Net 的原生客户端,方便应用集成;
- 支持 Spring Placeholder,Annotation 和 Spring Boot 的 ConfigurationProperties,方便应用使用(需要 Spring 3.1.1+);
- 同时提供了 Http 接口,非 Java 和 .Net 应用也可以方便地使用;
- 提供开放平台 API
- Apollo 自身提供了比较完善的统一配置管理界面,支持多环境,多数据中心配置管理、权限、流程治理等特性。不过 Apollo 出于通用性考虑,不会对配置的修改做过多的限制,只要符合基本的格式就能保存,不会针对不同的配置值进行针对性的校验,如数据库用户名、密码、Redis 服务地址等;
- 对于这类应用配置,Apollo 支持应用方通过开放平台 API 在 Apollo 进行配置的修改和发布,并且具备完善的授权和权限控制;
- 统一管理不同环境、不同集群的配置
四、热门配置中心框架
TIP:
按开源时间排序
-
Disconf
2014 年 7 月百度开源的配置管理中心,专注于各种【分布式系统配置管理】的【通用组件】和【通用平台】,提供的统一【配置管理服务】。目前已经不再维护更新;
https://github.com/knightliao/disconf
-
Spring Cloud Config
2014 年 9 月开源,Spring Cloud 生态组件,可以和 Spring Cloud 体系无缝整合;
https://github.com/spring-cloud/spring-cloud-config
-
Apollo
2016 年 5 月,携程开源的配置管理中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景;
https://github.com/ctripcorp/apollo
-
Nacos
2018 年 6 月,阿里开源的配置中心,也可以做 DNS 和 RPC 的服务发现;
https://github.com/alibaba/nacos
Ⅱ 快速使用
Maven 工程集成 Apollo
TIP:
此步骤建立在《搭建 Apollo 环境》之上;
-
测试数据
访问 apollo-portal 统一配置管理中心添加测试数据
-
因为我们此时的 apollo 数据是空的,因此我们需要在登陆之后点击创建项目来创建一个新的项目用于测试;
-
填写基本的信息后点击提交完成创建;
TIP:
部门:选择 Apollo 为我们提供好的样例部门即可;
应用id:最好不要使用中文,id 用于标识我们的项目;
应用名称:顾名思义
应用负责人:选择 apollo 为我们提供的管理员用户 apollo 即可;
-
完成创建后,点击左上角的 apollo logo 会发现我们已经创建的项目;
-
点击进入到我们新建的项目,找到新建配置并点击;
-
通过 key-value 的方式创建配置项;
-
点击提交后会发现是未发布的状态,此时我们需要点击发布按钮,让其生效;
-
当状态为已发布的状态,即可;
-
-
创建普通 Maven 工程并引入依赖
-
创建 Maven 工程
-
添加 Apollo 相关依赖
<dependencies> <!-- Apollo 提供客户端依赖--> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.28</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build>
-
-
编写测试代码
-
创建一个测试类
ApolloTest.java
;package wiki.lxmuuuu; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigService; public class ApolloTest { public static void main(String[] args) { // 通过 Apollo 服务端提供的 getAppConfig 方法获取读取数据的 Config 对象; Config config = ConfigService.getAppConfig(); // key 为配置项的 key 值 String key = "test"; // 通过 getProperty 方法读取某一个 ky 值,null:如果没有获取到则使用此默认参数,不需要则设置为 null String value = config.getProperty(key,null); System.out.println("value:" + value); } }
-
-
添加启动参数
TIP:
此时我们虽然已经编写好测试类,但还无法正常访问我们配置的 Apollo,因为我们还没有告诉程序如何去连接我们的 Apollo,所以我们则需要进行一些配置;
-
使用启动参数的方式添加配置
-
点击 idea 界面上方的 【add Configuration…】
-
点击左上角的 + 号添加一个【Application】
-
选择 Main class 为我们的测试类,VM options 则是我们的启动参数
启动参数:-Dapp.id=apollo-test -Denv=dev -Ddev_meta=http://localhost:8080
- -Dapp.id 是我们的 Apollo 项目的 appid;
- -Denv 是我们选择的环境,默认为 dev 环境;
- -Ddev_meta 是我们的 apollo-configservice 的访问 ip;
-
点击 【Apply】后点击【OK】完成配置;
-
-
-
代码测试
-
测试结果如下:
-
Spring Boot 工程集成 Apollo
TIP:
此步骤建立在《搭建 Apollo 环境》之上;
-
添加测试数据
-
添加一个新的 Apollo 项目
-
新增一个 namespace
-
进入到项目中点击左下角的【添加 Namespace】
-
点击【创建 Namespace】来创建一个新的 Namespace
-
填写必要信息,点击提交
- 名称:创建 namespace 的 id,默认项是会把之前我们选择的部门作为前缀
- 类型:选择 private 因为我们只在我们的项目中使用,不用公开
-
-
添加 mybatis 配置项
-
在我们新创建的 Namespace 下创建配置项
-
创建 spring 以及 mybatis 的基础配置
TIP:
Key 值必须要和我们之前在
application.properties
中 = 前面的值对应,Value 则是与 = 后的配置对应,建议从原有项目进行拷贝 -
apollo 中添加的配置项与之前项目中的配置项对比:
-
-
发布我们新增的 namespace
-
到这里,我们测试数据配置完毕;
-
-
创建 Spring Boot 工程
-
创建普通的 Spring Boot 工程即可
-
-
引入依赖&相关配置
-
引入本次测试需要的相关依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.1.0</version> </dependency>
-
配置
application.yml
app: id: apollo-mybatis-test apollo: meta: http://localhost:8080 bootstrap: namespaces: TEST1.mybatis enabled: true eagerLoad: enabled: true #spring: # datasource: # url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai # driver-class-name: com.mysql.cj.jdbc.Driver # username: root # password: Hate.Trouble2003 #mybatis: # configuration: # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # type-aliases-package: wiki.lxmuuuu.pojo # mapper-locations: classpath:mappers/*.xml
- 下面的 spring mybatis 配置都是注释掉的;
- app.id:项目的 appId
- apollo.meta:apollo-configservice 的 ip
- apollo.boostrap.namespace:指定项目中加载的 namespace,这里写入我们创建的 Namespace 即可;如果要加载多个 Namespace,用
,
分割,如:TEST1.mybatis,TEST1.activemq - apollo.boostrap.enabled:让 apollo 配置生效
- apollo.boostrap.eagerLoad.enabled:开启 apollo 配置的加载
-
-
编写测试代码
TIP:
数据库结构:
-
在 Spring Boot 启动类上添加
@EnableApolloConfig
注解package wiki.lxmuuuu; import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableApolloConfig @SpringBootApplication public class ApolloMybatisBootApplication { public static void main(String[] args) { SpringApplication.run(ApolloMybatisBootApplication.class, args); } }
-
编写实体类
Department.java
package wiki.lxmuuuu.pojo; import lombok.Data; @Data public class Department { private Integer id; private String name; }
-
编写
DepartmentMapper.java
package wiki.lxmuuuu.mapper; import org.apache.ibatis.annotations.Mapper; import wiki.lxmuuuu.pojo.Department; import java.util.List; @Mapper public interface DepartmentMapper { List<Department> getList(); }
-
编写
DepartmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="wiki.lxmuuuu.mapper.DepartmentMapper"> <select id="getList" resultType="department"> select `id` as `id`, `name` as `name` from `department` </select> </mapper>
-
编写测试类
TIP:
当中的 :@Value() 注解可以直接读取 apollo 配置项中的信息,:后则是如果从 apollo 中没有找到此信息,则使用的默认值
package wiki.lxmuuuu; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import wiki.lxmuuuu.mapper.DepartmentMapper; import wiki.lxmuuuu.pojo.Department; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest() class ApolloMybatisBootApplicationTests { @Autowired private DepartmentMapper departmentMapper; @Value("${testKey:testValueDefault}") private String testValue; @Test void test() { List<Department> list = departmentMapper.getList(); list.forEach(System.out::println); System.out.println("-----------------------------"); System.out.println("testValue:" + testValue); } }
-
-
测试代码
-
如果想测试 @Value,则需要在 apollo 统一配置管理界面新增以下配置项:
-
测试结果:
-
Ⅲ 深入学习 Apollo
Apollo 的执行流程
- 具体执行流程如下:
- 用户在 Apollo 配置中心对配置进行修改并发布
- 配置中心通知 Apollo 客户端有配置更新
- Apollo 客户端从配置中心拉去最新的配置、更新本地配置并通知到应用