1. 程式人生 > >spring boot 2.0.3+spring cloud (Finchley)6、配置中心Spring Cloud Config

spring boot 2.0.3+spring cloud (Finchley)6、配置中心Spring Cloud Config

repo 相互 class AS 默認 分布式系 配置信息 上傳 RR

Spring Cloud Config 是用來為分布式系統中的基礎設施和微服務應用提供集中化的外部配置支持,它分為服務端與客戶端兩個部分。其中服務端也稱為分布式配置中心,它是一個獨立的微服務應用,用來連接配置倉庫並為客戶端提供獲取配置信息、加密 / 解密信息等訪問接口;而客戶端則是微服務架構中的各個微服務應用或基礎設施,它們通過指定的配置中心來管理應用資源與業務相關的配置內容,並在啟動的時候從配置中心獲取和加載配置信息。Spring Cloud Config 實現了對服務端和客戶端中環境變量和屬性配置的抽象映射,所以它除了適用於 Spring 構建的應用程序之外,也可以在任何其他語言運行的應用程序中使用。由於 Spring Cloud Config 實現的配置中心默認采用 Git 來存儲配置信息,所以使用 Spring Cloud Config 構建的配置服務器,天然就支持對微服務應用配置信息的版本管理,並且可以通過 Git 客戶端工具來方便的管理和訪問配置內容。當然它也提供了對其他存儲方式的支持,比如:SVN 倉庫、本地化文件系統。

Config Server從本地讀取配置文件

本地倉庫是指將所有的配置文件統一寫在Config Server工程目錄下。config server暴露Http API接口,config client通過調用config server的Http API接口來讀取配置文件。

新建一個主maven項目,指定spring boot版本2.0.3,spring cloud版本 Finchley.RELEASE。

<?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> <groupId>com.cralor</groupId> <artifactId>chap10-config</artifactId> <version
>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>chap10-config</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.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.RELEASE</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</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> <!--使用aliyun鏡像--> <repositories> <repository> <id>alimaven</id> <name>Maven Aliyun Mirror</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

構建Config Server

在主maven工程下,新建一個module工程config-server,pom文件繼承主maven工程的pom文件,引入Config Server的起步依賴。

<?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>

    <groupId>com.cralor</groupId>
    <artifactId>config-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>config-server</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>com.cralor</groupId>
        <artifactId>chap10-config</artifactId>
        <version>0.0.1-SNAPSHOT</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>
    </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>

    <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.yml做相關配置:端口號8769,程序名config-server,spring.profiles.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

在gcresources目錄下新建shared文件夾,存放配置文件,新建文件config-client-dev.yml,用作eureka-client工程的dev(開發環境)的配置文件。在config-client-dev.yml配置文件中,指定端口號8762,定義一個變量foo,值為foo version 1。

server:
  port: 8762
foo: foo version 1

構建Config Client

新建工程config-client,該工程作為Config Client從Config Server讀取配置文件,pom文件繼承主maven工程的pom文件,引入Config Server的起步依賴web的起步依賴(已在主maven工程pom中配置)。

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

在配置文件bootstrap.yml中做相關配置。註意,這些與 Spring Cloud Config 相關的屬性必須配置在 bootstrap.yml 中,config 部分內容才能被正確加載,因為 config 的相關配置會先於 application.yml,而 bootstrap.yml 的加載也是先於 application.yml。指定程序名config-client,向Url地址為http://localhost:8769的Config Server讀取配置文件。如果沒有讀取成功則執行快速失敗(fail-fast),讀取的是dev文件。配置文件中的變量{spring.application.name}和{spring.profiles.active},兩者以 “-” 相連,構成了向Config Server讀取的配置文件名,config-client-dev.yml。

spring:
  application:
    name: config-client
  profiles:
    active: dev
  cloud:
    config:
      uri: http://localhost:8769
      fail-fast: true

在config-client工程寫一個API測試接口,讀取配置文件的foo變量並返回。

@RestController
public class MyController {

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

    @RequestMapping("/foo")
    public String hi(){
        return foo;
    }
}

啟動工程config-server,再啟動config-client,此時控制臺會顯示config-client向Url地址為http://localhost:8769的Config Server讀取了配置文件,程序的啟動端口為8762。

技術分享圖片

瀏覽器訪問http://localhost:8762/foo,顯示

技術分享圖片

可見,config client成功向config server讀取了配置文件。

Config Server從遠程Git倉庫讀取配置文件

Config Server從遠程Git倉庫讀取配置文件,可以將配置統一管理,並且可以通過Spring Cloud Bus在不人工啟動程序的情況下對Config Client的配置進行刷新。本例采用的是GitHub作為遠程Git倉庫。

修改Config Server的配置文件application.yml。

server:
  port: 8769
spring:
  application:
    name: config-server

  cloud:
    config:
      server:
        git:
          uri: https://github.com/cralor7/springcloud
          search-paths: config-repo
        #  username:
        #  password:
          default-label: master

uri為GitHub倉庫的地址,search-paths為遠程倉庫中配置文件所在路徑,username和password為GitHub倉庫的登錄名和密碼,如果是私有的倉庫登錄名和密碼是必須的,公開的倉庫可以不需要,default-label為倉庫的分支,本例是從master讀取。

將config-client-dev.yml稍作修改,上傳到GitHub倉庫中,

技術分享圖片

依次重啟config-server,config-client,控制臺

技術分享圖片

瀏覽器訪問http://localhost:8763/foo

技術分享圖片

可見,config-server從遠程倉庫讀取了配置文件,config-client從config-sever讀取了配置文件。

構建高可用的Config Server

當服務實例很多時,所有的服務實例需要同時從配置中心Config Server讀取配置文件,這時可以考慮將配置中心Config Server做成一個微服務,並且將其集群化,從而達到高可用。Config Server和Config Client向Eureka Server註冊,且將Config Server多實例部署。

構建Eureka Server

新建eureka-server工程,pom文件繼承主maven的pom文件引入Eureka Server和web的起步依賴。

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

配置文件application.yml做相關配置,指定端口號8761,並不自註冊(將register-with-eureka和fetch-registry設置為false)。

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

啟動類加註解@EnableEurekaServer

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

改造Config Server

作為Eureka Client需要在pom文件引入Eureka Client的起步依賴

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>

啟動類加註解@EnableEurekaClient

@EnableEurekaClient
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {

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

在配置文件application.yml指定註冊服務註冊的地址

server:
  port: 8769
spring:
  application:
    name: config-server

  cloud:
    config:
      server:
        git:
          uri: https://github.com/cralor7/springcloud
          search-paths: config-repo
         # username:
         # password:
          default-label: master
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

改造Config Client

和Config Server一樣加入Eureka Client的起步依賴,啟動類加註解@EnableEurekaClient,配置文件bootstrap.yml中,指定註冊服務註冊的地址http://localhost:8761/eureka/,向service-id為config-server的配置服務讀取配置文件。

spring:
  application:
    name: config-client
  profiles:
    active: dev
  cloud:
    config:
      fail-fast: true
      discovery:
        enabled: true
        service-id: config-server

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

依次啟動eureka-server和config-server(config-server開啟兩個實例,端口號8768、8769),成功後啟動config-client。通過控制臺可以看到config-client向地址為http://localhost:8768的config-server讀取了配置文件,瀏覽器訪問http://localhost:8763/foo,顯示

技術分享圖片

多次啟動config-client工程(我測試的時候重啟了4、5次),控制臺可以看到它會輪流從http://localhost:8768和http://localhost:8769的Config Server讀取配置文件,並做了負載均衡。

技術分享圖片

技術分享圖片

使用Spring Cloud Bus刷新配置

Spring Cloud Bus 通過輕量消息代理連接各個分布的節點,可以用於廣播配置文件的更改或者服務的監控管理。一個關鍵的思想就是,消息總線可以為微服務做監控,也可以實現應用程序之間相互通信。Spring Cloud Bus可選的消息代理組件包括RabbitMQ和Kafka等。這裏用RabbitMQ作為Spring Cloud的消息組件去刷新更改微服務的配置文件。

為什麽用Spring Cloud Bus去刷新配置呢?

如果有幾十個微服務,而每一個服務優勢多實例,當更改配置時,需要重啟多個微服務實例。Spring Cloud Bus的一個功能就是讓這個過程變得簡單,當遠程Git倉庫的配置文件更改後,只需要向某一個微服務實例發送一個Post請求,通過消息組件通知其他微服務實例重新去倉庫拉取最新的配置文件。

技術分享圖片

改造config-server

pom文件添加依賴,這 4 個是必須的,

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>

配置文件application.yml

server:
  port: 8769
spring:
  application:
    name: config-server

  cloud:
    config:
      server:
        git:
          uri: https://github.com/cralor7/springcloud
          search-paths: config-repo
         # username:
         # password:
          default-label: master
    bus:
      trace:
        enabled: true
      enabled: true

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

改造config-client

pom文件,這5個是必需的,還要加上web的起步依賴(已在主maven工程pom中配置)

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-bus</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

配置文件bootstrap.yml

server:
  port: 8763
spring:
  application:
    name: config-client
  profiles:
    active: test
  cloud:
    config:
      fail-fast: true
      discovery:
        enabled: true
        service-id: config-server
    bus:
      trace:
        enabled: true
      enabled: true

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

在需要更新的配置類上加@RefreshScope註解,@RefreshScope必須加,否則客戶端會收到服務端的更新消息,但是更新不了,因為不知道更新哪裏的。

@RefreshScope
@RestController
public class MyController {

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

    @RequestMapping("/foo")
    public String hi(){
        return foo;
    }
}

依次啟動eureka-server、config-server和config-client(config-client開啟兩個實例,端口號8762、8763),訪問瀏覽器http://localhost:8762/foo和http://localhost:8763/foo,顯示

技術分享圖片 技術分享圖片

更改遠程倉庫配置文件,將foo的值改為”foo: foo version 7“。通過Postman或其他工具發送一個Post請求http://localhost:8769/actuator/bus-refresh/,請求發送成功後,再訪問瀏覽器,顯示

技術分享圖片 技術分享圖片

可見,通過向8769端口的服務端發送Post請求刷新配置,由於使用了Spring Cloud Bus,其他服務實例(如兩個客戶端)也會接收到刷新配置的消息,也會刷新配置。

對客戶端config-client使用 /actuator/bus-refresh。首先需要把config-client上的bus-refresh端點給放出來

更改config-client的配置文件,發送Post請求http://localhost:8762/actuator/bus-refresh/。

server:
  port: 8763
spring:
  application:
    name: config-client
  profiles:
    active: test
  cloud:
    config:
      fail-fast: true
      discovery:
        enabled: true
        service-id: config-server
    bus:
      trace:
        enabled: true
      enabled: true

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

測試後可見8762、8763端口客戶端都發生了改變。說明只要開啟 Spring Cloud Bus 後,不管是對 config-server 還是 config-client 執行/actuator/bus-refresh都是可以更新配置的。

局部刷新

某些場景下(例如灰度發布),我們可能只想刷新部分微服務的配置,此時可通過/actuator/bus-refresh/{destination}端點的 destination 參數來定位要刷新的應用程序。例如:/actuator/bus-refresh/customers:8000,這樣消息總線上的微服務實例就會根據 destination 參數的值來判斷是否需要要刷新。其中,customers:8000指的是各個微服務的 ApplicationContext ID。destination 參數也可以用來定位特定的微服務。例如:/actuator/bus-refresh/customers:**,這樣就可以觸發 customers 微服務所有實例的配置刷新。

參考:Spring Cloud(九):配置中心(消息總線)【Finchley 版】

技術分享圖片

spring boot 2.0.3+spring cloud (Finchley)6、配置中心Spring Cloud Config