跟我學SpringCloud | 第七篇:Spring Cloud Config 配置中心高可用和refresh

SpringCloud系列教程 | 第七篇:Spring Cloud Config 配置中心高可用和refresh

Springboot: 2.1.6.RELEASE

SpringCloud: Greenwich.SR1

如無特殊說明,本系列教程全採用以上版本

1. 引言

上一篇我們聊了Spring Cloud Config 配置中心,並且和Github做了集成,我們的Server端是單機版的,任何單機版的服務都只能使用與測試環境或者自己做Demo測試,生產環境嚴禁使用單機服務,配置中心在整個微服務體系中都是及其重要的一個節點,尤其是在DevOps中自動擴容,如果配置中心宕機,那麼所有的自動擴容都會失敗。

所以這一篇我們聊聊配置中心的高可用,說到高可用,在springcloud體系中,是有註冊中心的,那麼,我們的配置中心也是一個服務,可不可以使用Eureka做服務的註冊與發現呢?

答案是肯定的。

2. Serve端

我們將上一篇的Serve端Copy到新的目錄中,增加Eureka-client的依賴,使得Config-Serve可以註冊到Eureka上。

2.1 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>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.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>Greenwich.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <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>

2.2 配置文件application.yml

server:
  port: 8080
spring:
  application:
    name: spring-cloud-config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/meteor1993/SpringCloudLearning
          search-paths: chapter6/springcloud-config
          username: username
          password: password
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

增加eureka的地址配置

2.3 啓動類

啓動類增加@EnableEurekaClient激活對註冊中心的支持

package com.springcloud.configserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigServerApplication {

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

}

這樣Server註冊端我們就修改完成了。先啓動Eureka,再啓動Serve,在瀏覽器中訪問http://localhost:8761/,就可以看到我們的Serve端已經註冊到註冊中心了,接下來我們開始改造Client端。

3. Client端

首先還是將上一篇的Client端Copy過來,和Server端一樣,增加Eureka-client的依賴,使得Config-Client可以從註冊中心上發現服務。

3.1 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>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.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>Greenwich.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <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>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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>

3.2 bootstrap.properties

這裏我們需要先清空application.yml,所有的配置全都轉移到bootstrap.properties中。

spring.application.name=spring-cloud-config-client
server.port=8081

spring.cloud.config.name=springcloud-config
spring.cloud.config.profile=dev
spring.cloud.config.label=master
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.serviceId=spring-cloud-config-server

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

主要是去掉了spring.cloud.config.uri直接指向server端地址的配置,增加了最後的三個配置:

  • spring.cloud.config.discovery.enabled :開啓Config服務發現支持
  • spring.cloud.config.discovery.serviceId :指定server端的name,也就是server端spring.application.name的值
  • eureka.client.serviceUrl.defaultZone :指向註冊中心的地址

3.3 啓動類

啓動類增加@EnableEurekaClient激活對註冊中心的支持

package com.springcloud.configclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class ConfigClientApplication {

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

}

4. 高可用

現在我們來模擬生產環境。

首先,順次啓動Eureka,Server,Client。

在idea啓動兩個config-serve,我們修改idea配置啓動配置,換到8000端口啓動config-serve。

先訪問http://localhost:8761/,可以看到兩個config-serve都正常註冊到註冊中心。

如上圖就可發現會有兩個server端同時提供配置中心的服務,防止某一臺down掉之後影響整個系統的使用。

我們訪問client端的鏈接:http://localhost:8081/hello, 可以看到頁面正常顯示:hello dev update1,刷新幾次,顯示都沒問題,現在我們隨機停掉一個端口的config-serve服務,再去刷新頁面,可以發現,頁面依然可以正常顯示:hello dev update1。

至此,我們高可用的目的已經達到,但是,不知道各位有沒有映像,我們上一篇留了一個坑,服務啓動後,我們修改遠端github上的配置時,這個配置並不會實時被客戶端端所獲取到,下面我們來聊一聊有關Spring Cloud Config 刷新的問題。

5. refresh

我們的客戶端並不能主動去感知Git或者Svn的配置變化,從而主動獲取最新的配置。那麼,客戶端如何去主動獲取新的配置信息呢?springcloud已經給我們提供瞭解決方案,每個客戶端通過POST方法觸發各自的/refresh。

修改config-client項目已到達可以refresh的功能。

5.1 添加依賴pom.xml

在我們原有的config-client項目的pom.xml的基礎增加新的依賴

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

增加了spring-boot-starter-actuator包,spring-boot-starter-actuator是一套監控的功能,可以監控程序在運行時狀態,其中就包括/refresh的功能。

5.2 開啓更新機制

需要給加載變量的類上面加載@RefreshScope,在客戶端執行/refresh的時候就會更新此類下面的變量值。

package com.springcloud.configclient.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: shiyao.wei
 * @Date: 2019/7/4 16:19
 * @Version: 1.0
 * @Desc:
 */
@RestController
@RefreshScope // 使用該註解的類,會在接到SpringCloud配置中心配置刷新的時候,自動將新的配置更新到該類對應的字段中。
public class HelloController {

    @Value("${springcloud.hello}")
    private String hello;

    @RequestMapping("/hello")
    public String from() {
        return this.hello;
    }
}

5.3 配置文件bootstrap.properties

spring.application.name=spring-cloud-config-client
server.port=8081

spring.cloud.config.name=springcloud-config
spring.cloud.config.profile=dev
spring.cloud.config.label=master
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.serviceId=spring-cloud-config-server

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

management.security.enabled=false
management.endpoints.web.exposure.include=*
  • management.security.enabled: springboot 1.5.X 以上默認開通了安全認證,所以需要添加這個配置
  • management.endpoints.web.exposure.include: springboot 2.x 默認只開啓了info、health的訪問,*代表開啓所有訪問

5.4 測試

我們先訪問客戶端的測試連接:http://localhost:8081/hello, 這時,頁面的顯示是:hello dev update1,我們修改github上的信息,修改爲:hello dev update,現在訪問http://localhost:8081/hello,得到的信息還是:hello dev update1,現在我們刷新一下客戶端,通過cmd命令行執行:curl -X POST http://localhost:8081/actuator/refresh,可以看到命令行上有顯示:["springcloud.hello","config.client.version"],意味着springcloud.hello這個配置已經刷新,這時,我們再去刷新一下頁面,可以看到,頁面上得到的信息已經變爲了:hello dev update,這時我們refresh成功。

每次手動刷新客戶端還是很麻煩,有沒有什麼辦法只要提交代碼就自動調用客戶端來更新呢,github的webhook是一個好的辦法。

6. webhook

WebHook是當某個事件發生時,通過發送http post請求的方式來通知信息接收方。Webhook來監測你在Github.com上的各種事件,最常見的莫過於push事件。如果你設置了一個監測push事件的Webhook,那麼每當你的這個項目有了任何提交,這個Webhook都會被觸發,這時Github就會發送一個HTTP POST請求到你配置好的地址。

如此一來,你就可以通過這種方式去自動完成一些重複性工作,比如,你可以用Webhook來自動觸發一些持續集成(CI)工具的運作,比如Travis CI;又或者是通過 Webhook 去部署你的線上服務器。下圖就是github上面的webhook配置。

  • Payload URL: 觸發後回調的URL
  • Content type: 數據格式,兩種一般使用json
  • Secret: 用作給POST的body加密的字符串。採用HMAC算法
  • events: 觸發的事件列表
events事件類型 描述
push 倉庫有push時觸發。默認事件
create 當有分支或標籤被創建時觸發
delete 當有分支或標籤被刪除時觸發

這樣我們就可以利用hook的機制去觸發客戶端的更新,但是當客戶端越來越多的時候hook支持的已經不夠優雅,另外每次增加客戶端都需要改動hook也是不現實的。其實Spring Cloud給了我們更好解決方案,我們在下一篇接着聊。

示例代碼-Github

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章