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


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的起步依賴,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>

在配置文件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的起步依賴,配置文件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請求,通過消息組件通知其他微服務實例重新去倉庫拉取最新的配置文件。

由於使用了RabbitMQ,首先必需安裝RabbitMQ。此處略...,(我安裝時去官網下載了最新的Erlang和RabbitMQ,結果杯具了...,安裝RabbitMQ時,Erlang的環境變量已經配置成功了結果還提示 ERLANG_HOME 找不到,原來Erlang和RabbitMQ還有版本匹配問題,從OTP 21.0一直到OTP 19.3,才終於可以了。附下載地址:ErlangrabbRabbitMQ )

改造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 版】

 

案例代碼地址:https://github.com/cralor7/springcloud 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM