七. SpringCloud服務配置

1. SpringCloud Config概述

1.1 分散式系統面臨的配置問題

微服務意味著要將單體應用中的業務拆分成一個一個子服務,每個服務的粒度相對較小,因此系統中會出現大量的服務。由於每個服務都需要必要的配置才能運行,所以一套集中式的,動態的配置管理設施是必不可少的。

SpringCloud提供了Config Server來解決這個問題,否則我們每一個微服務自己帶著一個application.yml,上百個配置文件的管理會令人頭疼。

1.2 是什麼

如圖,服務配置中心從遠端讀取配置文件,然後客戶端服務再通過服務配置中心讀取配置。

image-20210304100514213

SpringCloud Config為微服務架構中的微服務提供集中化的外部配置支援,配置伺服器為 各個不同微服務應用 的所有環境提供了一個 中心化的外部配置

SpringCloud Config分為服務端和客戶端兩部分:

  • 服務端也稱為 分散式配置中心,它是一個獨立的微服務應用 ,用來連接配置伺服器並為客戶端提供獲取配置資訊,加密/解密資訊等訪問介面,將配置資訊以REST介面的形式暴露給客戶端(客戶端可以用REST風格方式讀取到該配置資訊)。

  • 客戶端則是通過指定的配置中心來管理應用資源,以及與業務相關的配置內容,並在啟動的時候從配置中心獲取和載入配置資訊。配置伺服器默認採用git來存儲配置資訊,這樣就有助於對環境配置進行版本管理,並且可以通過git客戶端工具來方便的管理和訪問配置內容。

1.3 作用
  • 集中管理配置文件
  • 不同環境不同配置,動態化的配置更新,分環境比如dev/test/prod/beta/release
  • 運行期間動態調整配置,不再需要在每個服務部署的機器上編寫配置文件,服務會向配置中心同意拉取配置自己的資訊
  • 當配置發生改變時,服務不需要重啟即可感知到配置的變化並應用新的配置
  • 將配置資訊以REST介面的形式暴露 (post/crul訪問刷新即可)
1.4 與GitHub整合配置

由於SpringCloud Config默認使用Git來存儲配置文件(也有其他方式,比如支援SVN和本地文件),但最推薦還是Git,而且使用的是http/https的訪問形式。

2. Config 服務端配置與測試

2.1 Gitee倉庫

在Gitee上新建一個用作配置中心的新倉庫,並克隆到本地開發硬碟目錄

然後根據新建的Git地址,將Gitee上的倉庫克隆到本地

git clone //gitee.com/mp2333/springcloud-config.git
2.2 建Module

新建Module:cloud-config-center-3344作為配置中心微服務

在其POM文件中引入服務配置中心的依賴:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-config-server</artifactId>
</dependency>

修改其配置文件application.yml如下:

server:
  port: 3344

spring:
  application:
    name:  cloud-config-center # 註冊進Eureka伺服器的微服務名
  cloud:
    config:
      server:
        git:
          uri: //gitee.com/mp2333/springcloud-config.git # GitHub上面的git倉庫名字
          # 搜索目錄
          search-paths:
            - springcloud-config
          # 注意:如果倉庫私有則需要添加username/password
      # 讀取分支
      label: master

# 服務註冊到eureka地址
eureka:
  client:
    service-url:
      defaultZone: //eureka7001.com:7001/eureka

編寫主啟動類,在主啟動類上添加註解 @EnableConfigServer 使3344微服務具有配置中心功能:

@SpringBootApplication
@EnableConfigServer
public class ConfigCenterMain3344 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigCenterMain3344.class);
    }
}

修改hosts文件,增加映射,使本機模擬網址服務配置中心網址:

127.0.0.1 config-3344.com
2.3 GitHub倉庫建配置文件

如圖,就是創建了一個簡單的配置文件,用來測試能否通過配置中心微服務獲取內容。

image-20210304115026592

2.4 測試

配置讀取規則 (五種)

  • /{label}/{application}-{profile}.yml
# master分支
//config-3344.com:3344/master/config-dev.yml
//config-3344.com:3344/master/config-prod.yml
# dev分支
//config-3344.com:3344/dev/config-dev.yml
//config-3344.com:3344/dev/config-prod.yml
  • /{application}-{profile}.yml 默認master分支
//config-3344.com:3344/config-dev.yml
//config-3344.com:3344/config-prod.yml
  • /{application}/{profile}[/{label}]
# master分支
//config-3344.com:3344/config/dev/master
//config-3344.com:3344/config/prod/master
# dev分支
//config-3344.com:3344/config/dev/dev
//config-3344.com:3344/config/prod/dev

先啟動Eureka服務註冊中心,然後啟動服務配置中心微服務3344,訪問 //config-3344.com:3344/master/config-dev.yml ,我們可以看到3344微服務可以成功的讀取到遠端的配置文件。

image-20210304115204331

所以現在,服務配置中心從遠端Git倉庫讀取配置文件這一部分已經搭建完成:

image-20210304111342933

3. Config 客戶端配置與測試

3.1 建Moudle

新建Module:cloud-config-client-3355作為訪問配置中心的客戶端

在其POM文件中引入Config配置中心客戶端的啟動類:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
3.2 編寫配置文件bootstrap.yml

application.yml是用戶級的資源配置項,而bootstrap.yml是系統級的資源配置項,bootstrap.yml的優先順序更高,SpringCloud會創建一個”Bootstrap Context”,作為Spring應用的「Application Context”的 父上下文。初始化的時候,「Bootstrap Context”負責從外部源載入配置屬性並解析配置,這兩個上下文共享一個從外部獲取的”Environment」。」Bootstrap「屬性有高優先順序,默認情況系,它們不會被本地配置覆蓋。”Bootstrap Context”和”Application Context”這兩個上下文有不同的約定,所以新增一個bootstrap.yml文件,保證這兩個上下文的配置分離。

所以,要將Client模組下的application.yml文件改為bootstrap.yml,這是很關鍵的,因為bootstrap.yml是比application.yml先載入的。編寫bootstrap配置文件如下:

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    # Config客戶端配置
    config:
      label: master # 分支名稱
      name: config # 配置文件名稱
      profile: dev # 讀取後綴名稱   
      # 上述3個綜合:master分支上config-dev.yml的配置文件被讀取
      uri: //localhost:3344 # 配置中心地址
      # //config-3344.com:3344/master/config-dev.yml

# 服務註冊到eureka地址
eureka:
  client:
    service-url:
      defaultZone: //eureka7001.com:7001/eureka

編寫3355服務的主啟動類,之後編寫其業務類:

@RestController
public class ConfigClientController {

    @Value("${server.info}") //配置中心config-dev.yml配置的內容
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }
}
3.3 測試

下面測試客戶端是否能夠通過訪問配置中心獲取配置資訊

按順序啟動Eureka服務註冊中心,Config服務配置中心後,啟動我們的服務配置中心客戶端3355進行測試:

image-20210304115758589

3.4 存在的問題

我們在GitHub上修改配置文件內容,刷新3344配置中心服務端,發現Config Server配置中心立刻響應並刷新了配置資訊,但是!我們刷新3355客戶端Config Client,發現沒有任何響應,配置資訊仍然是原來的配置資訊。

難道每次遠端修改了配置文件後,客戶端都需要重啟來進行對配置資訊的重新載入嗎?

4. Config 客戶端之動態刷新

為了避免每次遠端更新配置資訊都需要重啟客戶端微服務3355來載入更新的配置資訊,我們需要使用動態刷新。

4.1 修改3355模組

在POM中引入actuator監控:

其實actuator依賴幾乎處了是網關的微服務外都得加。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
4.2 修改配置文件

bootstrap.yml中加入如下配置 暴露監控端點

# 暴露監控端點
management:
  endpoints:
    web:
      exposure:
        include: "*"
4.3 @RefreshScope註解

在業務類Controller上添加@RefreshScope註解使客戶端服務具有刷新功能:

@RestController
@RefreshScope
public class ConfigClientController {

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }

}
4.4 發送Post請求刷新客戶端3355

該刷新請求必須發送後,客戶端才能獲得刷新後的資訊,刷新客戶端的請求必須是POST請求:

curl -X POST "//127.0.0.1:3355/actuator/refresh"

當出現以上資訊時激活刷新客戶端3355成功,再次訪問客戶端,發現已經可以得到刷新後的配置資訊。

但是假設如果我們有多個微服務客戶端呢?難道每個微服務都需要執行一次POST請求進行手動刷新嗎?事實上我們可以通過廣播的方式進行一次通知,處處生效,這裡就要知道消息匯流排 => SpringCloud Bus。