1.前言
上一篇文章已經實現了Spring Cloud Config分佈式配置中心的功能,我們已經可以通過Config Server獲取Git遠程倉庫配置文件中的內容,但是在實際項目中,當服務實例數量比較多的情況下,每個服務單元都從配置中心獲取配置信息,假如配置中心由於網絡等原因掛掉了,這時候會導致那些服務實例請求失敗等一系列問題。這時候可以考慮將配置中心做成一個微服務,註冊到Eureka中,這樣啓動多個Config Server就可以實現負載均衡,從而實現配置中心的高可用。
2.準備工程
springcloud-eureka-server: 服務註冊中心,端口7001
springcloud-config-server-8585 高可用配置中心,端口8585
springcloud-config-client-8484 具體服務單元,端口8484
3.新建springcloud-config-server-8585工程
因爲要將配置中心作爲一個服務註冊到eureka中,所以注意引入config-server以及eureka的依賴,具體pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud0310</artifactId>
<groupId>com.bruceliu.springcloud0310</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-server-8585</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Eureka客戶端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</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>
</project>
4.啓動類加上@EnableConfigServer以及@EnableDiscoverClient註解
package com.bruceliu;
/**
* @BelongsProject: springcloud0310
* @BelongsPackage: com.bruceliu
* @Author: bruceliu
* @QQ:1241488705
* @CreateTime: 2020-03-12 22:03
* @Description: 實際項目中當服務單元很多時,每個服務單元都從配置中心讀取文件,這時可以將配置中心做成一個微服務(註冊到eureka),將其集羣化(負載均衡),達到高可用
*/
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient // 開啓EurekaClient功能
//開啓分佈式配置功能
@EnableConfigServer
public class SpringcloudHignAvailabilityConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudHignAvailabilityConfigServerApplication.class, args);
}
}
@EnableConfigServer: 開啓分佈式配置功能
5.config-server的配置文件application.yml
配置文件需要配置git倉庫地址,訪問路徑,分支,訪問用戶名,密碼等,注意需要配置
#端口號
server:
port: 8585
#應用名稱
spring:
application:
name: hign-availability-config-server
cloud:
config:
server:
git:
#git遠程倉庫地址
uri: https://gitee.com/zhouxingchi12345/SpringCloudConfig.git
#訪問git倉庫的用戶名(公開倉庫不需要配置用戶名和密碼,私有倉庫才需要配置)
username: [email protected]
#訪問git倉庫的密碼
password: zhouxingchi54321
#git倉庫配置文件的路徑
search-paths: repository
#git倉庫分支(默認master)
label: master
#配置註冊到eureka服務註冊中心的地址
eureka:
client:
serviceUrl:
defaultZone: http://bruceliu:[email protected]:7002/eureka,http://bruceliu:[email protected]:7001/eureka,http://bruceliu:[email protected]:7003/eureka
instance:
prefer-ip-address: true
instanceId: hign-availability-config-server:8585
注意:這裏還需要將上篇文章解決中文亂碼的問題加到config-server中,防止出現中文亂碼問題,具體可以參考上篇文章。
6.新建config-client工程
注意加入spring-cloud-starter-config、 spring-cloud-starter-eureka依賴,具體pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud0310</artifactId>
<groupId>com.bruceliu.springcloud0310</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-client-8484</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Eureka客戶端 -->
<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-actuator</artifactId>
</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>
</project>
啓動類
package com.bruceliu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @BelongsProject: springcloud0310
* @BelongsPackage: com.bruceliu
* @Author: bruceliu
* @QQ:1241488705
* @CreateTime: 2020-03-12 16:58
* @Description: TODO
*/
@SpringBootApplication
@EnableEurekaClient // 開啓EurekaClient功能
public class ConfigClientApp {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApp.class, args);
}
}
7.config-client配置文件bootstrap.yml
注意名稱是bootstrap.yml
server:
port: 8484
#注意application-name(配置文件前綴)需要對應git倉庫中 config-client-dev、config-client-test、config-client-prod爲名稱的配置文件
spring:
application:
name: config-client
cloud:
config:
#指定當前所屬環境
profile: prod
discovery:
#開啓通過服務訪問config-server的功能
enabled: true
#指定配置中心註冊到eureka的serviceId(即config-server的application-name)
serviceId: hign-availability-config-server
#git倉庫分支
label: master
#配置註冊到eureka服務註冊中心的地址
eureka:
client:
registry-fetch-interval-seconds: 5 # 獲取服務列表的週期:5s
service-url:
defaultZone: http://bruceliu:[email protected]:7002/eureka,http://bruceliu:[email protected]:7001/eureka,http://bruceliu:[email protected]:7003/eureka
instance:
prefer-ip-address: true
ip-address: 127.0.0.1
spring.cloud.config.discovery.enabled:true 表示開啓通過服務訪問config-server功能
spring.cloud.config.discovery.serviceId:hign-availability-config-server 表示指定配置中心註冊到eureka的serviceId(即config-server的application-name)
8.新建GetPropertyFromConfigServerController
主要用於測試從git倉庫讀取配置文件內容
package com.bruceliu.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 測試客戶端從配置服務中心獲取配置文件中的內容
* @date 2018/9/17 22:05
*/
@RestController
//@RefreshScope註解的作用: 如果刷新了bean,那麼下一次訪問bean(即執行一個方法)時就會創建一個新實例。
@RefreshScope
public class GetPropertyFromConfigServerController {
private static Logger logger = LoggerFactory.getLogger(GetPropertyFromConfigServerController.class);
@Value("${com.springcloud.bruceliu.message}")
String message;
@RequestMapping("/getPropertyFromConfigServer")
public String getPropertyFromConfigServer() {
System.out.println(message);
String msg = "hello, i am " + message + ", i'm come from config server";
logger.info(msg);
return msg;
}
}
注意:需要加上@RefreshScope註解,主要是用於後面配置刷新用到。
@RefreshScope註解的作用: 如果刷新了bean,那麼下一次訪問bean(即執行一個方法)時就會創建一個新實例。
9.測試
分別啓動eureka-server、config-server,config-client項目,如圖
可以看到,config-server以及config-client都成功註冊到eureka。
這時我們訪問 http://localhost:8484/getPropertyFromConfigServer
可以看到,我們成功從git倉庫中獲取到配置文件中的內容。我們可以將config-server啓動多個實例,然後訪問 http://localhost:8484/getPropertyFromConfigServer,可以看到成功獲取配置信息,然後我們可以停掉其中一個config-server實例,我們繼續訪問 http://localhost:8484/getPropertyFromConfigServer,還是可以成功獲取git遠程倉庫的配置信息,這就實現了config-server的高可用。
下面我們聊聊配置刷新的問題,在實際項目中,假如我們修改了git倉庫中的配置文件的信息,這時候是不會立即生效的,下面我們先講下手動刷新的方法,實際項目中是通過Spring Cloud Bus消息總線的方式自動刷新遠程倉庫配置文件,這個有時間後續講解。
10.改造config-client
首先我們做一個測試,我們嘗試使用Git工具修改當前配置的內容,比如,將repository/config-client-prod.properties中的com.springcloud.wsh.message的值修改爲Spring Cloud Config分佈式配置中心(正式生產環境)-----HELLO,
這時候我們訪問http://localhost:8484/getPropertyFromConfigServer,
可以看到返回的配置內容還是舊的,並沒有同步更新。
下面我們開始改造config-client,在config-client的pom.xml中加入監控的依賴:spring-boot-starter-actuator
<!--開啓監控功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
acutator包含了/refresh刷新API,我們可以調用它來實現配置文件的刷新。
bootstrap.properties
#actuator配置
management.endpoints.enabled-by-default=true
management.endpoint.health.show-details=always
#management.endpoints.web.exposure.include=refresh,info,health
management.endpoints.web.exposure.include=*
management.endpoints.web.base-path=/actuator
a、重新啓動config-client,訪問一次http://localhost:3333/getPropertyFromConfigServer,可以看到當前的配置值:
b、修改Git倉庫配置文件中的com.springcloud.wsh.message值
c、再次訪問一次http://localhost:8484/getPropertyFromConfigServer,可以看到配置值沒有改變:
d、通過POST請求發送到http://localhost:8484/refresh,這時候不能通過瀏覽器,注意是post請求,否則會報錯
這裏我們使用postman發送post請求,如下圖:
e、我們再次訪問http://localhost:8484/getPropertyFromConfigServer,可以看到配置值已經是更新後的值
至此,我們通過actuator實現了手動刷新git遠程倉庫中的配置文件的內容。注意一下在config-client項目中的controller上需要加上@RefreshScope註解, 否則調用/refresh接口看不到更新的內容,筆者就是踩了這個坑,需要注意下。
如果在執行post請求時出現以下提示
postman攔截了我們的post請求,這是因爲springboot的安全攔截,由於我們需要測試是否刷新成功,我們可以在config-client的配置文件application.yml中加入
#忽略權限攔截
management:
security:
enabled: false
11.總結
本文主要講解了如何實現了高可用的Config Server配置中心以及利用Actuator暴露的refresh接口來實現配置的動態更新。通過前面幾篇文章的學習,我們主要學了Eureka服務註冊中心、Zuul網關路由、Ribbon負載均衡、Feign聲明式服務調用、Config服務配置中心,這時候我們可以抽象一個比較簡單的微服務架構圖: