统一配置中心

我们之前做单体应用的时候是直接把配置写在application.yml中,但是如果是采用微服务架构的模式进行开发,这样的方式会存在哪些问题呢?首先维护困难、安全因素、更新配置时项目需要重启等等。针对这些问题,本文主要讲述的就是Spring cloud config这个组件,使用该组件可以很好的处理如下问题。

原始做法的缺陷

1、维护困难:假如一个服务,由多人开发,其中A在开发的时候,修改了配置,B再来开发的时候,需要测试别的一些功能,这个时候配置文件已经被A修改得面目全非了,这就造成了冲突。

2、安全因素:而且处于安全因素考虑,公司项目线上的配置基本是不对开发公开的,特别是数据库的账号密码这种,基本是只有运维才知道,把配置放在项目里面的话,每个开发人员都能看到,这种情况就需要对配置文件进行隔离。

3、更新配置需要重启:线上更新配置是经常发生的事情,比如更新一点小小的配置,难道都需要重启吗?使用spring cloud config就可以解决这一点。

统一配置中心的架构

配置中心到时候也会作为一个服务,这些配置为了方便管理,我们都把它放到git上,使用git控制起来会比较方便。如下图所示,其中箭头代表数据流动的方向:

最开始是把配置放在远端的Git,如Gitlab,Github或者自己搭建的私服,config-server把配置从远端Git拉下来之后,放到本地Git。config-server与本地Git之间是双向流动的,既会把远端的Git放到本地中,假如远端Git不能访问了,也会从本地Git把配置拉出来,拿到配置之后,就可以给微服务模块来使用。shop和order这两个服务,需要集成config-client这个组件。这就是统一配置中心整体的架构。

Config Server端使用流程

1、引入相关依赖

因为Config配置中心也是作为一个Client服务注册到Eureka Server的,所以必须引入Eureka Client的依赖,作为一个Eureka Client注册到Eureka Server上面。作为统一配置中心,必不可少的引入SpringCloud Config组件的依赖:

 1<dependencies>
 2    <dependency>
 3        <groupId>org.springframework.cloud</groupId>
 4        <artifactId>spring-cloud-config-server</artifactId>
 5    </dependency>
 6    <dependency>
 7        <groupId>org.springframework.cloud</groupId>
 8        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 9    </dependency>
10</dependencies>

2、启动类加注解

在启动类上添加注解支持@EnableConfigServer,其实不难发现很多SpringCloud组件的使用方式是一致的,都是先引入依赖,然后添加启动类的注解等流程,在这里不但需要@EnableConfigServer这个注解,同时不要忘记这也是一个Eureka Client,所以Eureka Client的注解和配置也是必不可少的。

1@SpringBootApplication
2@EnableDiscoveryClient
3@EnableConfigServer
4public class ConfigApplication {
5    public static void main(String[] args) {
6        SpringApplication.run(ConfigApplication.class, args);
7    }
8}

application.yml 配置文件:

 1spring:
 2  application:
 3    name: config
 4  cloud:
 5    config:
 6      server:
 7        git:
 8          uri: https://gitee.com/zouchanglin/config-repo
 9          username: zouchanglin
10          password: 00101101010
11          # 指定配置文件存放的目录
12          basedir: /root/config
13eureka:
14  instance:
15    appname: config
16  client:
17    service-url:
18      defaultZone: http://localhost:8761/eureka

3、配置文件放入仓库

不难发现,我们在上面的配置文件中配置了Git的仓库地址、用户名以及密码,因为从架构图可以看出,其他服务组件配置文件需要放在一个Git仓库中,可以是Github、GitlabGit、Gitee或者是自己搭建的Git私服。我演示的时候直接放在了Gitee(码云)上面:

mark

4、尝试访问配置文件

接下来可以尝试访问一下是否生效,开始Eureka Server,然后启动统一配置中心注册到Eureka Server上面。

mark

可以看到,虽然我们只是在Master分支上提交一个order.yml,但是我们访问order.yml却无法访问,访问order-a.yml、order-b.yml、order-a.properties、order-b.properties、order-a.json、order-b.json却没有问题,也就是说SpringCloudConfig帮我们做了转换,那么具体的转换规则是什么呢?在日志里可以看到/{label}/{name}-{profiles}.yml的字样,这些分别代表的意义如下:

  • label:Git的分支,如master、dev、test、pre-release等等
  • name:服务名称,在这里订单服务则为 order
  • profiles:环境,比如测试环境、预上线环境、线上环境等

mark

Config Client端使用流程

1、引入Config Client依赖

1<dependency>
2    <groupId>org.springframework.cloud</groupId>
3    <artifactId>spring-cloud-config-client</artifactId>
4</dependency>

2、修改配置文件

将application.yml修改为bootstrap.yml,意思就是从指定的配置中心来获取配置文件,然后再执行启动SpringBoot的核心流程:

1spring:
2  application:
3    name: shop
4  cloud:
5    config:
6      discovery:
7        enabled: true
8        service-id: CONFIG
9      profile: test

修改为bootstrap.yml后,也从原来的图表变成了一朵云,意思就是从服务器(统一注册中心)获取了

mark

3、验证是否成功

在仓库中放置了 shop-test.yml 文件:

 1server:
 2  port: 8090
 3
 4eureka:
 5  client:
 6    service-url:
 7      defaultZone: http://localhost:8761/eureka/
 8
 9spring:
10  application:
11    name: shop
12
13env: test

还在仓库中放置了 shop-dev.yml 文件

 1server:
 2  port: 8090
 3
 4eureka:
 5  client:
 6    service-url:
 7      defaultZone: http://localhost:8761/eureka/
 8
 9spring:
10  application:
11    name: shop
12
13env: dev

两个配置文件的env属性不同,写一个Controller测试一下从统一配置中心拿到的配置文件的内容:

 1@RestController
 2@RequestMapping("/env")
 3public class EnvController {
 4
 5    @Value("${env}")
 6    private String env;
 7
 8    @GetMapping("print")
 9    public String printEnv(){
10        return env;
11    }
12}

当我们把bootstrap.yml中的profile属性设置为dev的时候,拿到的配置文件就是shop-dev.yml,此时访问打印环境属性的接口打印出来就是dev;当我们把bootstrap.yml中的profile属性设置为test的时候,拿到的配置文件就是shop-test.yml,此时访问打印环境属性的接口打印出来就是test:

mark

统一配置中心的高可用

在配置Eureka的高可用时,采用了相互注册的方式来实现高可用性。统一配置中心服务的高可用其实很简单,因为统一配置中心也Eureka的客户端,所以只要拥有足够的统一配置中心实例向Eureka Server注册即可实现高可用。由于是在本地开发环境,所以通过指定不同的端口号的方式来启动三个统一配置中心的实例:

1-Dserver.port=8080
2-Dserver.port=8081
3-Dserver.port=8082

在Eureka Server的界面可以看到,三个配置中心的实例已经注册到了Eureka Server上面:

mark

使用配置中心的注意点

http://localhost:8761/eureka/ 这个地址是默认的地址,假设我们改成其他的端口或者其他的IP地址就会报错找不到Eureka,其实要理解这一点并不难,因为要拿到配置文件的前提是得先找到统一配置中心的实例,统一配置中心的实例的前提是你得去Eureka Server上面找,前提是自身得注册到Eureka Server,但是此时并没有配置Eureka Server的注册地址,所以相当于与世隔绝是一个孤立的模块,自然会发生启动失败,所以关于Eureka Server的配置,无需由统一配置中心来分发,而是直接写在配置文件里即可。

当然还有一种方式,那就是指定统一配置中心的URL,这样就能直接找到统一配置中心的实例,在bootstrap.yml中:

 1spring:
 2  application:
 3    name: shop
 4  cloud:
 5    config:
 6      discovery:
 7        enabled: true
 8        service-id: CONFIG
 9      profile: dev
10      uri: http://localhost:8888

总结一下就是:

  • 方式一:先找到统一配置中心,获取配置,从配置中心给的配置中找到Eureka Server,再注册到Eureka Server
  • 方式二:先找到Eureka Server,从Eureka Server找配置中心,从而获取对应的配置(推荐做法)

另外还有一点需要注意,那就是如果你需要的配置文件是shop-dev.yml,Git仓库同时存在shop.yml与shop-dev.yml,那么统一配置中心在拉取配置文件的时候,会把shop.yml和shop-dev.yml两个文件同时拉取下来,并且进行内容合并,所以我们通常遵循如下原则,那就是公共的配置内容写在shop.yml(对于本例而言)中,不同环境的配置内容写在shop-dev.yml或者shop-test.yml中。