基本概念
使用場景
是一個分布式的配置中心。適用於微服務;
核心功能
- 集中管理不同環境,不同集群的配置;
- 配置修改后可以實時推送到應用端;
- 具備規范的權限,流程治理特性;
開發技術
- 服務端使用springboot,springcloud開發,打包后可以直接運行,無需安裝額外的tomcat;
- java客戶端不依賴任何框架,對Spring,SpringBoot的客戶端也有額外支持
- .net客戶端不依賴任何框架
概念
縮寫 | 全稱 | 說明 |
---|---|---|
FAT | 功能測試環境 | |
UAT | 集成測試環境 | |
PRO | 生產環境 | |
DEV | 開發環境 |
詳細功能
- 統一管理不同環境,不同集群,不同命名空間的配置;
- 同一份代碼可以部署在不同的集群,可以有不同的配置,比如zk地址
- 通過命名空間可以方便的支持不同應用共享同一份配置,同時還允許應用對共享的配置進行覆蓋;
- 配置修改實時生效 (用戶在后台修改完配置發布后,客戶端可以在1s內收到最新的配置並通知應用程序)
- 版本發布概念, (所有的配置發布都有版本概念,可以方便的支持配置的回滾)
- 灰度發布(配置發布后,支隊部分應用實例生效,等觀察一段時間后在推送給所有的應用)
- 權限管理,發布審核,操作審計
- 客戶端配置信息監控(方便的看到配置被哪些實例使用)
- 支持多種語言,java和.net ,通過http接口使用也是支持的;
- 提供開放平台api給到其它系統修改和發布操作;
- 部署簡單
后台使用
后台操作
- 創建項目
- 分配管理員,(管理項目的權限分配,創建集群,創建namespace)
- 分配配置的修改和發布權限
- 添加配置項 ,修改配置項
- 發布配置,回滾配置;
- 讀取配置是在應用端使用; 具體見客戶端接入文檔;
公共組件的操作
公共組件: 提供給應用使用的其它組織的客戶端代碼,比如cat的客戶端;本質上也是應用的一部分;
區別 : 通常情況下,公共組件的使用的配置由原始開發團隊維護,但是實際的應用在運行時,環境不一樣,所以我們也允許應用在實際使用的時候能夠覆蓋公共組件的部分配置;
需要自己創建自己唯一的namespace ;
公共組件的操作
- 創建項目
- 分配項目管理員權限
- 創建namespace
- 添加配置項,發布;
- 公共配置的讀取
- 應用關聯公共組件並覆蓋公共組件的配置項
集群獨立配置
- 添加集群,默認集群;
- 多個appId使用同一份配置
- 同公共組件,關聯namespace,寫入公共配置,或者覆蓋公共配置
灰度發布
操作
- 創建灰度
- 灰度配置
- 灰度規則的新增,修改
- 灰度發布
- 全量發布,放棄灰度
- 發布歷史
客戶端接入
要求:jdk1.7+ , guava15.0+
客戶端配置參數
- app.id (systemProperty > System Environment > springboot application.properties > META-INF/app.properties) 對應項目的id
- apollo.meta 訪問地址 (SystemProperty > SpringBoot > SystemEnvironment>/opt/settings/server.properties > app.properties)
- 本地緩存路徑 /opt/data/{appId}/config-cache/ key: apollo.cacheDir
- 環境配置 key : env
- 集群配置 key: apollo.cluster
客戶端依賴
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.1.0</version>
</dependency>
接入方式對比
接入方式 | 特點 |
---|---|
api | 靈活,功能完備 |
spring | placeholder方式 |
springboot | @ConfigurationProperties |
API接入
獲取application namespace配置
Config config = ConfigService.getAppConfig();
//config instance is singleton for each namespace and is never null
String value = config.getProperty(someKey, someDefaultValue);
獲取公共namespace
String somePublicNamespace = "CAT";
Config config = ConfigService.getConfig(somePublicNamespace);
//config instance is singleton for each namespace and is never null
String value = config.getProperty(someKey, someDefaultValue);
獲取非properties格式的namespace配置
Config config = ConfigService.getConfig("application.yml");
String value = config.getProperty(someKey, someDefaultValue);
xml格式文件獲取
String someNamespace = "test";
ConfigFile configFile = ConfigService.getConfigFile("test", ConfigFileFormat.XML);
String content = configFile.getContent();
事件監聽
Config config = ConfigService.getAppConfig();
//config instance is singleton for each namespace and is never null
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
System.out.println("Changes for namespace " + changeEvent.getNamespace());
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
System.out.println(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType()));
}
}
});
spring方式接入
基於xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:apollo="http://www.ctrip.com/schema/apollo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.ctrip.com/schema/apollo http://www.ctrip.com/schema/apollo.xsd">
<apollo:config order="2"/>
<!-- 這個是最復雜的配置形式,指示Apollo注入FX.apollo和application.yml namespace的配置到Spring環境中,並且順序在application前面 -->
<apollo:config namespaces="FX.apollo,application.yml" order="1"/>
<bean class="com.ctrip.framework.apollo.spring.TestXmlBean">
<property name="timeout" value="${timeout:100}"/>
基於javaconfig
//這個是最復雜的配置形式,指示Apollo注入FX.apollo和application.yml namespace的配置到Spring環境中,並且順序在application前面
@Configuration
@EnableApolloConfig(order = 2)
public class SomeAppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
@Configuration
@EnableApolloConfig(value = {"FX.apollo", "application.yml"}, order = 1)
public class AnotherAppConfig {}
springboot方式接入
直接配置屬性
#加載應用對應的application namespace的配置
apollo.bootstrap.enabled = true
#加載其它namespace 的配置
apollo.bootstrap.namespaces = application,FX.apollo,application.yml
#在日志系統啟動之前加載阿波羅
apollo.bootstrap.eagerLoad.enabled=true
其它說明
一些公共的注解
新增的spring注解
- @ApolloConfig
用來自動注入Config對象 - @ApolloConfigChangeListener
用來自動注冊ConfigChangeListener - @ApolloJsonValue
用來把配置的json字符串自動注入為對象
配置的遷移
配置的遷移
- apollo中創建對應的項目;
- 在應用中創建好META-INF/app.properties,並配置好;
- 原來的配置文件,轉換為properties,貼到apollo后台;
- 刪除本地的配置;
本地開發
- 修改 /opt/settins/server.properties
設置env = Local - 准備本地配置文件 位置:
Mac/Linux: /opt/data/{appId}/config-cache
Windows: C:\opt\data{appId}\config-cache - 修改本地配置不會檢測到實時變化,需要重啟應用;
現有項目改造步驟
- 去掉disconf的依賴,找到對應的xml,去掉申明的配置bean;
- 搜索對應的@Disf,如果在類上,直接去掉,如果在方法或者字段上,替換為@Value注解;
- 增加apollo的xml配置;
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:apollo="http://www.ctrip.com/schema/apollo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://code.alibabatech.com/schema/dubbo
http://files.sports.lifesense.com/xsd/dubbo.xsd
http://www.ctrip.com/schema/apollo
http://www.ctrip.com/schema/apollo.xsd">
<apollo:config order="1"/>
<apollo:config order="2" namespaces="lx-doctor.redis,lx-doctor.global,lx-doctor.filesystem,lx-doctor.kafka,lx-doctor.dubbo,log4j2.xml"/>
- 因為之前的依賴類路徑下存在mysql.properties ; 而apollo沒有生成那么多的文件;
- 在apollo后台,從disconf后台中把項目都有的配置放到application.properties下;
- 新建私有命名空間 log4j2.xml,把日志配置copy,放到里面發布;
- 如有跟公共配置相同的key,需要重寫的,則關聯公共命名空間重寫;
- 啟動程序,解決編譯錯誤;