一、前言
接下来是开展一系列的 SpringCloud 的学习之旅,从传统的模块之间调用,一步步的升级为 SpringCloud 模块之间的调用,此篇文章为第七篇,即介绍 Config分布式配置中心。
二、概述
2.1 目前的问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。
通俗一点就是假设一个项目被拆分成了几百个小的子服务,而每个小的子服务又有自己的 application.yml文件,如果要修改一些公共的东西,那么就需要这几百个小的子服务都进行修改,想想就比较可怕。
而 SpringCloud 提供了 ConfigServer来解决这个问题。
2.2 ConfigServer是什么
SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。如下图:
SpringCloud Config 分为服务端和客户端两部分。
服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。
客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用 git 来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过 git客户端工具来方便的管理和访问配置内容。
2.3 ConfigServer作用
**1、**集中管理配置文件
2、 不同环境不同配置,动态化的配置更新,分环境部署比如dev/test/prod/beta/release
**3、**运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。
**4、**当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置。
5、 将配置信息以 REST接口的形式暴露。
2.4 与 GitHub 整合配置
由于SpringCloud Config 默认使用 Git 来存储配置文件(也有其它方式,比如支持 SVN 和本地文件),但最推荐的还是 Git ,而且使用的是http/https访问的形式。
2.5 官网地址
官网的地址,在这块。
三、Config 服务端配置与测试
3.1 git Hub 相关操作
首先用你自己的账号在 GitHub 官网上新建一个名为springcloud-config 的新 Repository,如下图:
然后在实体库里面创建三个配置文件,分别用来模拟开发环境、测试环境和生产环境,名称和内容如下:
3.2 新建工程
新建一个cloud-config-center-3344 模块,将它设置成配置中心模块,pom.xml内容如下:
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>com.springcloud</groupId>
<artifactId>SpringCloud</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-config-center-3344</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<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.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yml 内容如下所示,需要配置 gitHub的代码地址和工程名字,以及分支的名称。
ruby
server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://github.com/BuGeiQianJiuZa/springcloud-config.git # GitHub上面的git仓库名字
####搜 索目录
search-paths:
- springcloud-config
#### 读取分支
label: master
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
主启动类的代码如下所示:
java
@SpringBootApplication
// 设置为配置中心的注解
@EnableConfigServer
public class ConfigCenterMain3344
{
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class, args);
}
}
在 windows 下修改 hosts文件,添加一个映射,如下:
3.3 测试
接下来测试下是否可以通过上面我们新建的微服务获取 GitHub 配置信息,启动 cloud-eureka-server7001 和 cloud-config-center-3344 模块,在浏览器输入:http://config-3344.com:3344/master/config-dev.yml,如下图,可以看到,可以正常读取配置文件的内容
3.4 配置读取规则
配置读取规则的意思就是可以通过哪种写法来读取配置文件的内容。其中 label 表示分支 branch ,name 表示服务名,profiles 表示环境 dev/test/prod 。application表示配置文件名称。
3.4.1 第一种
可以采用这种格式 /{label}/{application}-{profile}.yml来获取内容,如下图:
3.4.2 第二种
可以采用这种格式**/{application}-{profile}.yml**来获取内容,如下图:
3.5 小结
成功实现了通过 SpringCloud Config 读取 GitHub的配置信息。
四、Config 客户端配置与测试
4.1 新建工程
新建一个cloud-config-center-3355 模块作为客户端进行测试,pom.xml内容如下:
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>com.springcloud</groupId>
<artifactId>SpringCloud</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-config-client-3355</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
4.2 bootstrap 配置文件说明
如果像平常一样,我们需要创建一个application.yml 的配置文件,但这块我们要创建一个 bootstrap.yml 的配置文件。为什么呢?因为 applicaiton.yml 是用户级的资源配置项, bootstrap.yml是系统级的,优先级更加高。
Spring Cloud 会创建一个 Bootstrap Context ,作为 Spring 应用的 Application Context 的父上下文。初始化的时候,Bootstrap Context 负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的 Environment。
Bootstrap 属性有高优先级,默认情况下,它们不会被本地配置覆盖。Bootstrap context 和 Application Context 有着不同的约定,所以新增了一个bootstrap.yml 文件,保证Bootstrap Context 和 Application Context 配置的分离。
所以要将 Client 模块下的application.yml 文件改为bootstrap.yml ,这是很关键的,因为 bootstrap.yml 是比application.yml 先加载的。bootstrap.yml 优先级高于 application.yml。
ruby
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址k
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
4.3 配置业务类
主启动类的代码如下所示:
java
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3355
{
public static void main(String[] args)
{
SpringApplication.run(ConfigClientMain3355.class,args);
}
}
业务类的代码如下所示:
java
package com.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
// 获取的是 gitHub 上配置的 config.info 的值
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo()
{
return configInfo;
}
}
4.4 测试
分别启动 cloud-eureka-server7001 、cloud-config-center-3344 和 cloud-config-center-3355 模块,先访问 http://config-3344.com:3344/master/config-dev.yml,进行自测,如下图:
然后进行客户端测试访问,输入 http://localhost:3355/configInfo ,如下图,可以看到,也可以获取到 gitHub上的属性值。
4.5 小结
我们成功实现了客户端 3355 访问 SpringCloud Config3344 通过 GitHub获取配置信息。
4.6 分布式配置的动态刷新问题
假设此时 Linux 运维人员修改了 GitHub 上的配置文件内容做调整,比如说把 version 改成了 2,如下图:
刷新 3344 ,发现 ConfigServer配置中心立刻响应,如下图:
刷新 3355 ,发现 ConfigClient客户端没有任何响应,如下图:
3355没有变化,除非自己重启或者重新加载才可以读取最新的配置信息,难道每次运维修改配置文件,客户端都需要重启?
五、Config 客户端之动态刷新
5.1 相关配置
为了避免每次更新配置都要重启客户端微服务 3355 ,我们研究研究如何让客户端动态的刷新,首先修改 cloud-config-center-3355 模块,在 pom.xml中引入如下的依赖:
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
修改 bootstrap.yml配置文件,添加暴露监控端点,如下:
ruby
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址k
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
在业务类 ConfigClientController 中添加 @RefreshScope 注解,如下:
java
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo()
{
return configInfo;
}
}
此时启动 cloud-eureka-server7001 、cloud-config-center-3344 和 cloud-config-center-3355 模块,启动完成后将 version 的版本改成 3,如下图:
刷新 3344 ,发现 ConfigServer配置中心立刻响应,如下图:
刷新 3355 ,发现 ConfigClient客户端仍然没有任何响应,如下图:
5.2 发送 post 请求
这是因为还差了一个步骤:需要运维人员发送 Post 请求刷新 3355 ,即执行 curl -X POST "http://localhost:3355/actuator/refresh" 命令进行刷新,如下:
执行完该命令后,再次测试 3355,如下图:
可以看到,成功实现了客户端 3355刷新到最新配置内容。
5.3 问题思考
假设现在有几百个微服务的客户端,每个微服务都要执行一次 post 请求,都是需要手动刷新的嘛?能否有一种方式替换这种手动刷新的方式?接下来介绍消息总线来解决这个问题。