Apollo(阿波羅)是攜程框架部門研發的開源配置管理中心
能夠集中化管理應用不同環境、不同集群的配置,配置修改后能夠實時推送到應用端,並且具備規范的權限、流程治理等特性
地址 https://github.com/ctripcorp/apollo
特性
統一管理不同環境、不同集群的配置
配置修改實時生效(熱發布)
版本發布管理
灰度發布
權限管理、發布審核、操作審計
客戶端配置信息監控
提供Java和.Net原生客戶端
提供開放平台API
部署簡單
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.搭建 Apollo 配置中心
參照 https://github.com/ctripcorp/apollo/wiki/Quick-Start
(1)下載Quick Start安裝包
(2)創建Apollo服務端需要兩個數據庫
ApolloPortalDB
ApolloConfigDB
(3)解壓Quick Start安裝包,修改demo.sh數據庫配置
# apollo config db info apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8 apollo_config_db_username=root apollo_config_db_password=root # apollo portal db info apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8 apollo_portal_db_username=root apollo_portal_db_password=root
(4)服務啟動與關閉
在git下執行啟動腳本
./demo.sh start

關閉
./demo.sh stop

(5)瀏覽器打開http://localhost:8070/

輸入用戶名 apollo,密碼 admin

http://localhost:8080/

2.spring boot集成
(1)依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.6.0</version>
</dependency>
<!-- 為了編碼方便,並非apollo 必須的依賴 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
</dependencyManagement>
(2)啟動類
package com.xyz.provider; import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableApolloConfig public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
(3)配置
server.port=8010 spring.application.name=service-provider # 應用全局唯一的身份標識 app.id = springboot-apollo # Apollo Meta Server 地址 apollo.meta = http://localhost:8080 # 自定義本地配置文件緩存路徑 apollo.cacheDir = ./config # 設置在應用啟動階段就加載 Apollo 配置 apollo.bootstrap.enabled = true # 注入 application namespace apollo.bootstrap.namespaces = application apollo.bootstrap.eagerLoad.enabled = true logging.level.com.xyz.provider.controller=debug order.discount = 75
說明:
app.id:AppId是應用的身份信息,是配置中心獲取配置的一個重要信息
apollo.bootstrap.enabled:在應用啟動階段,向Spring容器注入被托管的application.properties文件的配置信息
apollo.bootstrap.eagerLoad.enabled:將Apollo配置加載提到初始化日志系統之前
logging.level.com.xyz.provider.controller:調整 controller 包的 log 級別,用來在配置中心動態配置日志級別
(4)控制器
package com.xyz.provider.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { private static Logger logger = LoggerFactory.getLogger(HelloController.class); @Value("${server.port}") String port; @Value(("${order.discount}")) Integer discount; @GetMapping("hello") public String hello(String name) { logger.debug("debug log..."); logger.info("info log..."); logger.warn("warn log..."); return "hello " + name + " ,i am from port:" + port + ",discount:" + discount; } }
啟動項目
GET http://localhost:8010/hello?name=beibei
返回
hello beibei ,i am from port:8011,discount:75
(5)配置
創建項目

說明:
部門:選擇應用所在的部門
應用AppId:用來標識應用身份的唯一id,格式為string,需要和客戶端application.properties中配置的app.id對應
應用名稱:應用名,僅用於界面展示
應用負責人:選擇的人默認會成為該項目的管理員,具備項目權限管理、集群創建、Namespace創建等權限
新增配置

發布配置
編輯完配置后,需要發布配置,才能生效

發布后再次請求http://localhost:8010/hello?name=beibei
返回 hello beibei ,i am from port:8011,discount:50
說明:
服務的端口依然還是 8010,因為 apollo 修改配置,不會像Spring Cloud Config 那樣去重啟應用
重啟應用后,客戶端會使用配置中心中配置的端口
2020-05-27 11:19:48.064 DEBUG 14880 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : debug log...
2020-05-27 11:19:48.064 INFO 14880 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : info log...
2020-05-27 11:19:48.064 WARN 14880 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : warn log...
說明:
在配置中心修改日志等級,發布后也沒法立即生效,需要重啟應用
重啟后
2020-05-27 11:21:57.780 INFO 13200 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : info log...
2020-05-27 11:21:57.780 WARN 13200 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : warn log...
添加監聽
package com.xyz.provider.config; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.spring.annotation.ApolloConfig; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LoggingSystem; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.util.Set; @Configuration public class LoggerConfig { private static final Logger logger = LoggerFactory.getLogger(LoggerConfig.class); private static final String LOGGER_TAG = "logging.level."; @Autowired private LoggingSystem loggingSystem; @ApolloConfig private Config config; @ApolloConfigChangeListener private void configChangeListter(ConfigChangeEvent changeEvent) { refreshLoggingLevels(); } @PostConstruct private void refreshLoggingLevels() { Set<String> keyNames = config.getPropertyNames(); for (String key : keyNames) { if (StringUtils.containsIgnoreCase(key, LOGGER_TAG)) { String strLevel = config.getProperty(key, "info"); LogLevel level = LogLevel.valueOf(strLevel.toUpperCase()); loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level); logger.info("{}:{}", key, strLevel); } } } }
說明:
@ApolloConfig注解:將Apollo服務端的中的配置注入到這個類中
@ApolloConfigChangeListener注解:監聽配置中心配置的更新事件,若該事件發生,則調用refreshLoggingLevels方法處理該事件
ConfigChangeEvent:獲取被修改配置項的key集合,以及被修改配置項的新值、舊值和修改類型等信息
2020-05-27 11:26:18.211 WARN 4636 --- [nio-8011-exec-4] c.x.provider.controller.HelloController : warn log...
Apollo與SpringCloud Config的對比| Apollo | Spring Cloud Config | |
| 配置界面 | 同一界面管理不同環境/集群配置 | 無,通過git操作 |
| 配置生效時間 | 實時 | 重啟生效,或Refresh,git hook+MQ |
| 版本管理 | 界面尚志傑提供發布歷史和回滾按鈕 | 無 |
| 灰度發布 | 支持 | 不支持 |
| 授權/審計/審核 | 界面直接操作,且支持修改和發布權限分離 | 需要通過git倉庫設置,且不支持修改和發布權限分離 |
| 實時配置監控 | 可以方便看到當前那些客戶端在使用哪些配置 | 不支持 |
| 配置獲取性能 | 快 | 較慢 |
| 客戶端支持 | 原生支持Java/.Net,提供API,支持Spring annotation | Spring應用+annotation支持 |
Apollo是企業生產級配置中心,使用范圍更廣
