Apollo简介
Apollo(阿波罗)是一款可靠的分布式配置管理中心,诞生于携程框架研发部,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
服务端基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器。
Java客户端不依赖任何框架,能够运行于所有Java运行时环境,同时对Spring/Spring Boot环境也有较好的支持。
.Net客户端不依赖任何框架,能够运行于所有.Net运行时环境。
官方文档:https://www.apolloconfig.com/#/zh/README
Apollo设计
总体设计
1、基础模型
- 用户在配置中心对配置进行修改并发布
- 配置中心通知Apollo客户端有配置更新
- Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用
2、架构模块
-
Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端
-
Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
-
Eureka提供服务注册和发现,为了简单起见,目前Eureka在部署时和Config Service是在一个JVM进程中的
-
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进程中
服务端设计
配置发布后的实时推送设计
上图简要描述了配置发布的大致过程:
- 用户在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核心概念
-
application (应用)
这个很好理解,就是实际使用配置的应用,Apollo客户端在运行时需要知道当前应用是谁,从而可以去获取对应的配置
关键字:appId
-
environment (环境)
配置对应的环境,Apollo客户端在运行时需要知道当前应用处于哪个环境,从而可以去获取应用的配置
关键字:env
-
cluster (集群)
一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。
关键字:cluster
-
namespace (命名空间)
一个应用下不同配置的分组,可以简单地把namespace类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,RPC配置文件,应用自身的配置文件等
关键字:namespaces
关系:应用包含多个环境,环境包含多个集群,集群中包含多个命名空间
Apollo安装
本例查用快速入门安装
参考:https://www.apolloconfig.com/#/zh/deployment/quick-start
1、下载一个Quick Start安装包,即可进行安装
2、安装数据库,快速安装包sql目录中有sql文件直接安装
3、修改demo.sh文件的数据库连接信息
4、如果安装阿里云服务器上,需要外网访问,需要保证对应三个端口能访问,且需要修改注册到Eureka使用外网ip
修改这一个地方即可,-Deureka.instance.ip-address=192.168.1.1(外网ip)
5、启动服务
启动命令:./demo.sh start
停止命令:./demo.sh stop
- http://127.0.0.1:8070 Apollo的 Portal 地址
- http://127.0.0.1:8080 Eureka注册中心地址,同时也是 Apollo的 Config Service地址
- http://127.0.0.1:8090 Apollo的 AdminService地址
Apollo使用
1、访问地址:http://127.0.0.1:8070,默认账号密码:apollo/admin, 创建Apollo项目,并发布配置
2、访问:http://127.0.0.1:8080 Eureka注册中心地址,同时也是 Apollo的 Config Service地址
3、使用Java客户端连接
创建Maven项目,引入依赖
<!-- apollo 依赖 --> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.7.0</version> </dependency>
编写代码
1 public class TestApollo { 2 3 // 方法一 启动JVM参数:-Dapp.id=apollo-quickstart -Denv=DEV -Dapollo.cluster=default -Dapollo.meta=http://127.0.0.1:8080 4 // 方法二 System.setProperty("apollo.meta", "http://config-service-url"); 5 public static void main(String[] args) throws InterruptedException { 6 7 8 Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null 9 String someKey = "sms.enable"; 10 String someDefaultValue = "------"; 11 String value = config.getProperty(someKey, someDefaultValue); 12 System.out.println("value = " + value); 13 14 while (true) { 15 value = config.getProperty(someKey, someDefaultValue); 16 System.out.printf("now: %s, sms.enable: %s%n", LocalDateTime.now().toString(), value); 17 Thread.sleep(3000L); 18 } 19 } 20 }
启动运行,注意加入JVM参数-Apollo的连接信息
可以在管理界面修改key的值,应用能够及时感应到变化,并使用最新值。俗称热发布
Apollo集成SpringBoot使用
1、新建SpringBoot项目,加入Apollo依赖
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>com.test</groupId> 8 <artifactId>test-springboot-apollo</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 11 <parent> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-parent</artifactId> 14 <version>2.2.5.RELEASE</version> 15 <relativePath/> <!-- lookup parent from repository --> 16 </parent> 17 18 <properties> 19 <maven.compiler.source>8</maven.compiler.source> 20 <maven.compiler.target>8</maven.compiler.target> 21 </properties> 22 23 <dependencies> 24 25 <dependency> 26 <groupId>org.springframework.boot</groupId> 27 <artifactId>spring-boot-starter-web</artifactId> 28 </dependency> 29 30 <dependency> 31 <groupId>org.springframework.boot</groupId> 32 <artifactId>spring-boot-starter-test</artifactId> 33 </dependency> 34 35 <!-- apollo 依赖 --> 36 <dependency> 37 <groupId>com.ctrip.framework.apollo</groupId> 38 <artifactId>apollo-client</artifactId> 39 <version>1.7.0</version> 40 </dependency> 41 42 </dependencies> 43 44 45 <!-- SpringBoot打包插件,可以将代码打包成一个可执行的jar包 --> 46 <build> 47 <plugins> 48 <plugin> 49 <groupId>org.springframework.boot</groupId> 50 <artifactId>spring-boot-maven-plugin</artifactId> 51 </plugin> 52 </plugins> 53 </build> 54 55 </project>
2、编写配置文件application.properties文件
# AppId是应用的身份信息,是配置中心获取配置的一个重要信息。 app.id=apollo-quickstart # apollo 缓存目录 apollo.cacheDir = ./apolloCacheDir # 在应用启动阶段,向Spring容器注入被托管的application.properties文件的配置信息。 apollo.bootstrap.enabled = true # 将Apollo配置加载提到初始化日志系统之前。这样日志配置可以托管到apollo apollo.bootstrap.eagerLoad.enabled=true # apollo 源信息 apollo.meta = http://127.0.0.1:8080/ # apollo 命名空间 apollo.bootstrap.namespaces = application
3、编写启动类代码
1 @SpringBootApplication 2 public class Application implements CommandLineRunner { 3 4 // apollo 支持 @Value注解 5 // sms.enable = false 6 @Value("${sms.enable}") 7 private String value; 8 9 // apollo 自己的json注解 10 // jsonArrayProperty = [{"someString":"hello","someInt":100},{"someString":"world!","someInt":200}] 11 @ApolloJsonValue("${jsonArrayProperty:[]}") 12 private List<Map<String, String>> jsonArrayProperty; 13 14 // apollo 自己的json注解 15 // jsonBeanProperty = {"someString":"hello","someInt":100} 16 @ApolloJsonValue("${jsonBeanProperty:{}}") 17 private Map<String, String> jsonBeanProperty; 18 19 public static void main(String[] args) { 20 SpringApplication.run(Application.class, args); 21 } 22 23 @Override 24 public void run(String... args) throws Exception { 25 System.out.println("value = " + value); 26 System.out.println("jsonArrayProperty = " + jsonArrayProperty); 27 System.out.println("jsonBeanProperty = " + jsonBeanProperty); 28 29 // while (true) { 30 // System.out.println("value = " + value); 31 // Thread.sleep(3000L); 32 // } 33 } 34 }
注意:
Apollo支持 @Value 注解,而且还有 apollo自带的注解 @ApolloJsonValue,可以解析json字符串
缓存文件格式:{appId}+{cluster}+{namespace}.properties
参考:
教程:http://www.pbteach.com/java/java_05_03/20210527/582534840956485632.html
博客:https://www.cnblogs.com/huanchupkblog/p/10509427.html