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