1,什么是分布式配置中心
項目中配置文件比較繁雜,而且不同環境的不同配置修改相對頻繁,每次發布都需要對應修改配置,如果配置出現錯誤,需要重新打包發布,時間成本較高,因此需要做統一的分布式注冊中心,能做到自動更新配置文件信息,解決以上問題
常用分布式配置中心框架
Disconf(依賴於zookpeer)、Zookpeer()、diamond、攜程(阿波羅)、Redis、xxl-conf
Zookpeer保證配置文件信息實時更新 (事件通知)
大型互聯網公司自己內部都有自己獨立分布式配置中心
獨立RPC、獨立分布式各種解決方案
注冊中心解決 rpc服務治理
分布式配置中心 解決分布式配置文件管理
Apollo阿波羅簡介
Apollo(阿波羅)是攜程框架部門研發的分布式配置中心,能夠集中化管理應用不同環境、不同集群的配置,配置修改后能夠實時推送到應用端,並且具備規范的權限、流程治理等特性,適用於微服務配置管理場景。
Apollo阿波羅特點
用戶在Apollo修改完配置並發布后,客戶端能實時(1秒)接收到最新的配置,並通知到應用程序。
統一管理不同環境、不同集群的配置
所有的配置發布都有版本概念,從而可以方便的支持配置的回滾。
配置修改實時生效(熱發布)
用戶在Apollo修改完配置並發布后,客戶端能實時(1秒)接收到最新的配置,並通知到應用程序
版本發布管理
所有的配置發布都有版本概念,從而可以方便的支持配置的回滾
灰度發布
支持配置的灰度發布,比如點了發布后,只對部分應用實例生效,等觀察一段時間沒問題后再推給所有應用實例。
權限管理、發布審核、操作審計
應用和配置的管理都有完善的權限管理機制,對配置的管理還分為了編輯和發布兩個環節,從而減少人為的錯誤。
所有的操作都有審計日志,可以方便的追蹤問題。
客戶端配置信息監控
可以方便的看到配置在被哪些實例使用
提供Java和.Net原生客戶端
提供了Java和.Net的原生客戶端,方便應用集成
支持Spring Placeholder, Annotation和Spring Boot的ConfigurationProperties,方便應用使用(需要Spring 3.1.1+)
同時提供了Http接口,非Java和.Net應用也可以方便的使用
提供開放平台API
Apollo自身提供了比較完善的統一配置管理界面,支持多環境、多數據中心配置管理、權限、流程治理等特性。
不過Apollo出於通用性考慮,對配置的修改不會做過多限制,只要符合基本的格式就能夠保存。
在我們的調研中發現,對於有些使用方,它們的配置可能會有比較復雜的格式,如xml, json,需要對格式做校驗。
還有一些使用方如DAL,不僅有特定的格式,而且對輸入的值也需要進行校驗后方可保存,如檢查數據庫、用戶名和密碼是否匹配。
對於這類應用,Apollo支持應用方通過開放接口在Apollo進行配置的修改和發布,並且具備完善的授權和權限控制
部署簡單
配置中心作為基礎服務,可用性要求非常高,這就要求Apollo對外部依賴盡可能地少
目前唯一的外部依賴是MySQL,所以部署非常簡單,只要安裝好Java和MySQL就可以讓Apollo跑起來
Apollo還提供了打包腳本,一鍵就可以生成所有需要的安裝包,並且支持自定義運行時參數
Apollo整體架構原理
上圖簡要描述了Apollo客戶端的實現原理:
- 客戶端和服務端保持了一個長連接,從而能第一時間獲得配置更新的推送。(通過Http Long Polling實現)
- 客戶端還會定時從Apollo配置中心服務端拉取應用的最新配置。
- 這是一個fallback機制,為了防止推送機制失效導致配置不更新
- 客戶端定時拉取會上報本地版本,所以一般情況下,對於定時拉取的操作,服務端都會返回304 - Not Modified
- 定時頻率默認為每5分鍾拉取一次,客戶端也可以通過在運行時指定System Property:
apollo.refreshInterval
來覆蓋,單位為分鍾。
- 客戶端從Apollo配置中心服務端獲取到應用的最新配置后,會保存在內存中
- 客戶端會把從服務端獲取到的配置在本地文件系統緩存一份
- 在遇到服務不可用,或網絡不通的時候,依然能從本地恢復配置
- 應用程序可以從Apollo客戶端獲取最新的配置、訂閱配置更新通知
2, Apollo 框架下載路徑github
https://github.com/ctripcorp/apollo
里面有開發,設計思想問文檔
3,下載完成,解壓
appollo-master 相當於是源碼,apollo-build-scripts-master相當於將好幾個服務集成到一塊,用shell 腳本demo.sh 一鍵啟動
4,將apollo-build-scripts-master 文件夾發送到虛擬機192.168.178.110 /usr/local 的路徑下、
5,打開apollo-build-scripts-master/sql 下兩個sql 文件,並且將他們刷入到數據庫,注意mysql 數據庫版本是要5.7 以上
6,配置demo.sh
#!/bin/bash
# apollo config db info
apollo_config_db_url=jdbc:mysql://192.168.178.110:3306/ApolloConfigDB?characterEncoding=utf8 apollo_config_db_username=root apollo_config_db_password=12345678
# apollo portal db info
apollo_portal_db_url=jdbc:mysql://192.168.178.110:3306/ApolloPortalDB?characterEncoding=utf8 apollo_portal_db_username=root apollo_portal_db_password=12345678
# =============== Please do not modify the following content =============== #
if [ "$(uname)" == "Darwin" ]; then
windows="0"
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
windows="0"
elif [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ]; then
windows="1"
else
windows="0"
fi
# meta server url
config_server_url=http://192.168.178.110:8080 admin_server_url=http://192.168.178.110:8090 eureka_service_url=$config_server_url/eureka/ portal_url=http://192.168.178.110:8070
需要修改的點,已經標注出來了,
數據庫,本來是安裝在了windows 系統上,也設置了可以遠程登陸,但是啟動的適合都連不上,所以直接在本機,安裝了linux版本的數據庫
配置完成,開始啟動
進入到//usr/local/apollo-build-scripts-master 輸入命令:
./demo.sh start
出現以下界面,則配置成功:
4,url 路徑所代表的意思:
從上圖中,可以看出幾個服務:
Config service:http://192.168.178.110:8080 給應用端調用
Portal service:http://192.168.178.110:8070
Admin Service:為了給Portal service 調用
Config service: 就是Eureka 注冊中心,將服務注冊到Eureka 上進行管理
Portal service:用戶名apollo 密碼admin 進入到了分布式配置中心web 界面
進入之后:
5,springboot 項目集成apollo
創建Java workding set,名稱分布式配置中心,在里面創建springboot 項目,導入maven
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.RC1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </exclusion> </exclusions> --> </dependency> <!-- apollo 攜程apollo配置中心框架 --> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-core</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.0.1</version> <executions> <execution> <id>copy-conf</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <encoding>UTF-8</encoding> <outputDirectory>${project.build.directory}/ext/conf</outputDirectory> <resources> <resource> <directory>ext/conf</directory> <includes> <include>logback.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.7.5.201505241946</version> <executions> <execution> <id>default-prepare-agent</id> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>default-prepare-agent-integration</id> <goals> <goal>prepare-agent-integration</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>0.4.3</version> <configuration> <imageName>hy_uav_gateway</imageName> <dockerDirectory>src/main/docker</dockerDirectory> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}.jar</include> <include>ext/conf/logback.xml</include> </resource> </resources> </configuration> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
6,將阿波羅build 到本地倉庫
因為以下這兩個包是需要引用Apollo 的包的,也就是之前Apollo-master 的源碼的包
<!-- apollo 攜程apollo配置中心框架 --> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-core</artifactId> <version>1.0.0</version> </dependency>
2中方式可以將源碼打入本地maven 倉庫,第一種,是將源碼導入到eclipse中,利用mvn -install 下
第二種方式就是在Apollo-master/scripts 下的build.bat 文件雙擊,就會自動將包build
build 完成之后,maven 倉庫就生成了Apollo的包
7,現在在將springboot 項目update ,就可以引用了。
8,創建 apollo-env.properties 去連接apollo 分布式配置中心
local.meta=http://192.168.178.110:8080
dev.meta=http://192.168.178.110:8080
fat.meta=${fat_meta}
uat.meta=${uat_meta}
lpt.meta=${lpt_meta}
pro.meta=${pro_meta}
9,在resources 文件夾下,建立appid ,一個appid,代表一個應用
10,因為項目有好幾種環境,有開發,測試,預生產,生產等,怎么區分apollo 分布式配置中心連的是那種環境呢
修改/opt/settings/server.properties(Mac/Linux)或C:\opt\settings\server.properties(Windows)文件,設置env為DEV:
env=DEV
11,springboot 測試,能否獲得配置中心的值
@RestController public class IndexController { @Value("${projectName:default}") private String projectName; @Value("${projectLeader:default}") private String projectLeader; @RequestMapping("/read") public String read() { return projectName + "===" + projectLeader; } }
啟動類:
@Configuration @EnableApolloConfig @SpringBootApplication @EnableAutoConfiguration public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
12,項目啟動之后,還需要在Apollo 配置中心上把projectName,projectLeader 這兩個key的value 添加,apllo 如何知道是哪個項目,就是根據appid
創建項目:
在項目上添加配置的值,支持回滾
13,測試成功