SpringCloud 系列教程 | 第七篇: Spring Cloud Config 配置中心高可用和 refresh
- Springboot: 2.1.6.RELEASE
- SpringCloud: Greenwich.SR1
如无特殊说明, 本系列教程全采用以上版本
上一篇我们聊了 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.YAML
- 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.YAML, 所有的配置全都转移到 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
来源: https://www.cnblogs.com/babycomeon/p/11135926.html