1. 程式人生 > >SpringCloud實戰7-Config分散式配置管理

SpringCloud實戰7-Config分散式配置管理

分散式環境下的統一配置框架,已經有不少了,比如百度的disconf,阿里的diamand

官方文件對spring Cloud Config的描述如下:

  Spring Cloud Config為分散式系統中的外部配置提供伺服器和客戶端支援,使用Config Server,您可以在所有環境中管理應用程式的外部屬性。客戶端和伺服器上的概念對映與Spring Environment和PropertySource抽象相同,

  因此它們與Spring應用程式非常契合,但可以與任何以任何語言執行的應用程式一起使用。隨著應用程式通過從開發人員到測試和生產的部署流程,您可以管理這些環境之間的配置,並確定應用程式具有遷移時需要執行的一切。

  伺服器儲存後端的預設實現使用git,因此它輕鬆支援標籤版本的配置環境,以及可以訪問用於管理內容的各種工具。很容易新增替代實現,並使用Spring配置將其插入。

1.為什麼要配置中心?

一個應用中不只是程式碼,還需要連線資源和其它應用,經常有很多需要外部設定的項去調整應用行為,如切換不同的資料庫,設定功能開關等。

隨著系統微服務的不斷增加,首要考慮的是系統的可伸縮、可擴充套件性好,隨之就是一個配置管理的問題。各自管各自的開發時沒什麼問題,到了線上之後管理就會很頭疼,到了要大規模更新就更煩了。

而且你不可能停止你的服務叢集去更新的你配置,這是不現實的做法,因此springcloud配置中心就是一個比較好的解決方案,下圖就是一個springcloud配置中心的解決方案:

常見的配置中心的實現方法有:

  1.硬編碼(缺點:需要修改程式碼,風險大)

  2.放在xml等配置檔案中,和應用一起打包(缺點:需要重新打包和重啟)

  3.檔案系統中(缺點:依賴作業系統等)

4.環境變數(缺點:有大量的配置需要人工設定到環境變數中,不便於管理,且依賴平臺) 5.雲端儲存(缺點:與其他應用耦合)

Spring Cloud Config就是雲端儲存配置資訊的,它具有中心化,版本控制,支援動態更新,平臺獨立,語言獨立等特性。其特點是:

  1.提供服務端和客戶端支援(spring cloud config server和spring cloud config client)
  2.集中式管理分散式環境下的應用配置
  3.基於Spring環境,無縫與Spring應用整合
  4.可用於任何語言開發的程式
  5.預設實現基於git倉庫,可以進行版本管理
  6.可替換自定義實現

spring cloud config包括兩部分:

  1.spring cloud config server 作為配置中心的服務端:

    1.拉取配置時更新git倉庫副本,保證是最新結果

    2.支援資料結構豐富,yml, json, properties 等

    3.配合 eureke 可實現服務發現,配合 cloud bus 可實現配置推送更新

    4.配置儲存基於 git 倉庫,可進行版本管理

    5.簡單可靠,有豐富的配套方案

  2.Spring Cloud Config Client 客戶端:

    1.Spring Boot專案不需要改動任何程式碼,加入一個啟動配置檔案指明使用ConfigServer上哪個配置檔案即可

SpringCloud Config與百度的disconf之類的有很大不同,主要區別在於下面三點:

  1.配置的儲存方式不同:disconf是把配置資訊儲存在mysql、zookeeper中,而spring cloud config是將配置儲存在git/svn上 (即:配置當成原始碼一樣管理)

  2.配置的管理方式不同:spring cloud config沒有類似disconf的統一管理介面,既然把配置都當成git之類的原始碼來看待了,git的管理介面,就是配置的管理介面

  3.配置變化的通知機制不同:disconf中配置變化後,依賴zk的事件watcher來通知應用,而spring cloud config則是依賴git每次push後,觸發webhook回撥,最終觸發spring cloud bus(訊息匯流排),然後由訊息匯流排通知相關的應用。

從配置變化的通知機制上看,如果有100個應用節點,都依賴於統一配置,如果修改了配置,只想讓某幾個節點"灰度"更新配置,spring cloud config server更容易做到,這一點相對disconf更靈活

首先SpringCloud Config 是分為Server端和Client端的,Server端負責管理配置,Client端用來載入配置。我們每一個為服務都要整合一個Client端的。上面也提到過。因此,我們現在看一下Config的Server端的Demo實現。

首先在原來的專案中新建一個springcloud-config-server模組,並且引入相關依賴,如下:

複製程式碼

  <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>1.4.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.3.5.RELEASE</version>
    </dependency>

複製程式碼

我們可以看到引入了Eureka,為什麼呢?很明顯是為了高可用。

接著在啟動類上面加入@EnableConfigServer註解,表示這裡是配置中心服務。還有Eureka的客戶端的註解程式碼如下:

複製程式碼

@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigApplication {

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

複製程式碼

application.yml配置如下:

複製程式碼

server:
  port: 7000
#服務名字
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
#git 倉庫的地址
          uri: https://gitee.com/xxxx/springcloud-config.git
#git 倉庫的賬號密碼
          username: xxx
          password: xxx
#加入註冊中心,實現高可用
eureka:
  client:
    service-url:
       defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

複製程式碼

注意了,前提是你必須要在git倉庫中先建立一個倉庫,然後配置兩個配置,一個開發dev,一個測試test  如下圖:

dev的內容如下:

test的內容如下:

好了,讓我們把springcloud-config模組啟動起來,啟動啟動類,執行,訪問git倉庫中的cloud-config-dev.properties,如下:

接下來,我們進行springcloud Config的Client端的Demo,如下:

首先引入Client端的相關依賴,如下:

複製程式碼

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <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>
            <version>1.4.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.3.5.RELEASE</version>
        </dependency>

複製程式碼

這裡提一下,為什麼需要引入前面的actuctor依賴,因為,我們Client端需要在不重啟的情況下,及時更新拉取載入配置中心的改變,然後修改記憶體中的配置的值。 

接著在Client啟動類的打上@EnableDiscoveryClient的註解,來註冊到註冊中心去,如下:

複製程式碼

@SpringBootApplication
@EnableDiscoveryClient
public class ConfigClientApplication {

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

複製程式碼

接下來這步驟很關鍵,就是要將Client模組下的application.yml檔案改為bootstrap.yml,這是很關鍵的,因為bootstrap.yml是比application.yml先載入的。bootstrap.yml優先順序高於application.yml。就好比如,你應用程式都跑起來了,你配置還沒載入,這不是扯淡嗎?

如下:

複製程式碼

server:
  port: 7005
spring:
  application:
    name: cloud-config
  cloud:
    config:
#啟動什麼環境下的配置,dev 表示開發環境,這跟你倉庫的檔案的字尾有關,比如,倉庫配置檔案命名格式是cloud-config-dev.properties,所以profile 就要寫dev
      profile: dev
#面向服務,允許被發現
      discovery:
        enabled: true
#這個名字是Config Server端的服務名字,不能瞎寫。
        service-id: config-server
#註冊中心
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
#是否需要許可權拉去,預設是true,如果不false就不允許你去拉取配置中心Server更新的內容
management:
  security:
    enabled: false

複製程式碼

 接著寫一段測試程式碼,如下,建立一個測試Controller,程式碼如下:

複製程式碼

@RestController
//這裡面的屬性有可能會更新的,git中的配置中心變化的話就要重新整理,沒有這個註解內,配置就不能及時更新
@RefreshScope
public class TestController {

    @Value("${name}")
    private String name;
    @Value("${age}")
    private Integer age;

    @RequestMapping("/test")
    public String test(){
        return this.name+this.age;
    }
}

複製程式碼

接著啟動啟動該工程,執行結果如下:

首先我們我們先看沒更新配置之前的值,如下:

接著我們去git倉庫中修改age的值為24,再用postman來發送post請求localhost:7005/refresh,如下:

可以看到postman返回config.client.version資訊,表示告知Client,遠端的倉庫中的配置中心已經更新了的配置版本資訊,改變的值為age。

接著我們繼續重新整理瀏覽器,localhost:7005/test,看一下年齡是否更新了,如下:

可以看到年齡跟新到24了。

但是這樣就好了嗎?雖然服務沒有重啟,但是我們要一個服務一個服務的傳送post請求,我們能受的了嗎?這比之前的沒配置中心好多了,那麼我們如何繼續避免挨個挨個的向服務傳送Post請求來告知服務,你的配置資訊改變了,需要及時修改記憶體中的配置資訊。

這時候我們就不要忘記訊息佇列的釋出訂閱模型。讓所有為服務來訂閱這個事件,當這個事件發生改變了,就可以通知所有微服務去更新它們的記憶體中的配置資訊。這時Bus訊息匯流排就能解決,這留到下一篇隨筆講解。