Spring Cloud實戰系列(六) - 分散式配置中心Spring Cloud Config

零壹技術棧發表於2019-02-02

相關

  1. Spring Cloud實戰系列(一) - 服務註冊與發現Eureka

  2. Spring Cloud實戰系列(二) - 客戶端呼叫Rest + Ribbon

  3. Spring Cloud實戰系列(三) - 宣告式客戶端Feign

  4. Spring Cloud實戰系列(四) - 熔斷器Hystrix

  5. Spring Cloud實戰系列(五) - 服務閘道器Zuul

  6. Spring Cloud實戰系列(六) - 分散式配置中心Spring Cloud Config

  7. Spring Cloud實戰系列(七) - 服務鏈路追蹤Spring Cloud Sleuth

  8. Spring Cloud實戰系列(八) - 微服務監控Spring Boot Admin

  9. Spring Cloud實戰系列(九) - 服務認證授權Spring Cloud OAuth 2.0

  10. Spring Cloud實戰系列(十) - 單點登入JWT與Spring Security OAuth

前言

分散式系統 中,由於服務數量巨多,為了方便 服務配置檔案統一管理實時更新,所以需要 分散式配置中心 元件。 Spring Cloud 提供的 分散式配置中心 元件是 Spring Cloud Config,它支援將 配置服務 放在配置服務的 記憶體 中(即 本地),也支援放在 遠端 Git 倉庫中。Spring Cloud Config 提供了兩個角色,一個是 Config Server,二個是 Config Client

正文

1. Config Server從本地讀取配置檔案

建立一個新的 Spring Boot 專案模組,取名為 config-server,它的 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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>io.github.ostenant.springcloud</groupId>
    <artifactId>config-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>config-server</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Dalston.RELEASE</spring-cloud.version>
    </properties>

    <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>
    </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>
        </plugins>
    </build>
</project>
複製程式碼

在應用啟動類上使用 註解 @EnableConfigServer 開啟 配置伺服器

@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
複製程式碼

需要在程式的 配置檔案 application.properties 裡面進行如下配置。通過 spring.profile.active=native 來配置 Config Server本地讀取配置,讀取的路徑為 Classpath 下的 shared 目錄。

server:
  port: 8769
spring:
  application:
    name: config-server
  profiles:
    active: native
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared
複製程式碼

src/main/resources 目錄下新建 shared 資料夾,在 shared 資料夾下新建一個 config-client-dev.yml 檔案。

server:
  port: 8762
foo: foo version 1
複製程式碼

執行 ConfigServerApplicationmain() 方法,在 8769 埠啟動 Config Server 應用程式。

2. 構建Config Client

建立一個 Spring Boot 專案模組,取名為 config-client,它的 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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>io.github.ostenant.springcloud</groupId>
    <artifactId>config-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>config-client</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Dalston.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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>
        </plugins>
    </build>
</project>
複製程式碼

resources 目錄下新建 bootstrap.yml 檔案,因為 bootstrap 相對於 application 具有 優先的執行順序

變數 {spring.application.name}{spring.profiles.active},兩者使用 “-” 相連,作為 Config ClientConfig Server 讀取的 配置檔名

bootstrap.yml

spring:
  application:
    name: config-client
  cloud:
    config:
      uri: http://localhost:8769
      fail-fast: true # 讀取沒有成功,執行快速失敗
  profiles:
    active: dev
複製程式碼

配置一個介面,用於測試 讀取配置檔案foo 變數,並通過 API 介面返回客戶端。

@RestController
@SpringBootApplication
public class ConfigClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }

    @Value("${foo}")
    private String foo;

    @RequestMapping(value = "/foo")
    public String foo(){
        return foo;
    }
}
複製程式碼

啟動 config-client 應用程式,訪問 http://localhost:8762/foo,服務端的響應資料如下:

foo version 1

可見 config-client 成功地從 config-server 專案的 shared 本地檔案目錄 讀取到 配置檔案 config-client-dev.yml 中的 foo 變數。

3. Config Server從遠端Git倉庫讀取配置檔案

修改 config-server 的配置檔案 application.yml,程式碼如下.

server:
  port: 8769
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://coding.net/ostenant/config-repo
          search-paths: test
          username: ostenant@163.com
          password: xxxx
      label: master
複製程式碼

如果 Git 倉庫為 公開倉庫,可以不填寫 使用者名稱密碼;如果是 私有倉庫 則需要填寫,本例子配置了一個 私有倉庫

配置 解釋
spring.cloud.config.server.git.uri 配置git倉庫地址
spring.cloud.config.server.git.searchPaths 配置倉庫路徑
spring.cloud.config.label 配置倉庫的分支
spring.cloud.config.server.git.username 訪問git倉庫的使用者名稱
spring.cloud.config.server.git.password 訪問git倉庫的使用者密碼

遠端倉庫 https://coding.net/ostenant/config-repo 中有個 名為 config-client-dev.properties配置檔案,裡面配置有一個屬性:

foo = foo version 2
複製程式碼

重新啟動應用程式 config-serverconfig-client,再次訪問 http://localhost:8762/foo,服務端的響應資料如下:

foo version 2

可見,config-server 從遠端 Git 倉庫讀取了 配置檔案,進一步 config-clientconfig-server 讀取了相關的 配置屬性

4. 構建高可用的Config Server

配置中心 config-server 做成一個 微服務,並且將其 叢集化,從而實現 高可用

4.1. 改造Config Server

Config Server 中引入 Eureka 客戶端的 起步依賴 spring-cloud-starter-eureka

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
複製程式碼

在應用的 啟動類 上加上 註解 @EnableEurekaClient,將 Config Server 註冊到 Eureka Server 上面。

在配置檔案 application.yml 加入 服務註冊地址

eureka:
  client:
    service-url:
      defaultZone: http://locahost:8761/eureka/
複製程式碼

4.2. 改造Config Client

同樣的在 Config Client 中引入 Eureka 客戶端的 起步依賴 spring-cloud-starter-eureka

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
複製程式碼

在應用的 啟動類 上加上 註解 @EnableEurekaClient,將 Config Client 註冊到 Eureka Server 上面。

在配置檔案 application.yml 加入 服務註冊地址

eureka:
  client:
    service-url:
      defaultZone: http://locahost:8761/eureka/
複製程式碼

在配置檔案 application.yml 加入相關配置,從 service-idconfig-server配置服務 讀取相關 配置檔案

spring:
  application:
    name: config-client
  cloud:
    config:
      fail-fast: true
      discovery:
        enabled: true
        service-id: config-server
  profiles:
    active: dev
server:
  port: 8762
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
複製程式碼

重新啟動應用程式 config-serverconfig-client,再次訪問 http://localhost:8762/foo,服務端的響應資料如下:

foo version 2

只需要啟動多個 config-server 例項,即可搭建一個 高可用config-server 叢集。

5. 使用Spring Cloud Bus重新整理配置

Spring Cloud Bus分散式節點 通過輕量級的 訊息代理 連線起來。它可以用於 廣播配置檔案 的更改或者 服務之間 的通訊,也可以用於 監控。在 分散式配置檔案 被更改後,可以通過 Spring Cloud Bus 通知各個微服務中的即時重新整理 本地配置

5.1. 改造config-client

config-clientpom.xml 裡面加入 起步依賴 spring-cloud-starter-bus-amqp

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
複製程式碼

在專案的配置檔案 application.yml 檔案中新增 RabbitMQ 的相關配置,包括 RabbitMQ地址使用者名稱密碼。為了方便驗證,將 management.security.enabled 改為 false

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
management.security.enabled=false
複製程式碼

最後,在需要更新屬性的 配置類 上加 @RefreshScope 註解。

@RefreshScope
@RestController
@SpringBootApplication
public class ConfigClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }

    @Value("${foo}")
    private String foo;

    @RequestMapping(value = "/foo")
    public String foo(){
        return foo;
    }
}
複製程式碼

依次啟動應用,啟動兩個 config-client 例項, 分別為 87628763。啟動完成後,訪問 http://localhost:8762/foo 或者 http://localhost:8763/foo,服務端響應資料如下:

foo version 2

更改遠端Git 倉庫 配置檔案config-client-dev.properties,將 foo 的值改為 “foo version 3”

訪問 http://localhost:8762/bus/refresh 請求 重新整理配置,設定 “destination” 引數為 待重新整理 屬性的 服務名稱。例如 “http://localhost:8762/bus/refresh?destination=config-client:**”,即 重新整理服務名config-client 的所有 服務例項

Spring Cloud實戰系列(六) - 分散式配置中心Spring Cloud Config

再次訪問 http://localhost:8762/foohttp://localhost:8763/foo,服務端響應資料如下:

foo version 3

測試結果表明,/bus/refresh 通知服務名為 config-client 的所有例項 重新整理 了本地的 foo 屬性配置。

參考

  • 方誌朋《深入理解Spring Cloud與微服務構建》

歡迎關注技術公眾號: 零壹技術棧

零壹技術棧

本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。

相關文章