写点什么

spring cloud 篇之配置中心

作者:邱学喆
  • 2022 年 3 月 26 日
  • 本文字数:3409 字

    阅读完需:约 11 分钟

spring cloud篇之配置中心

一. 概述

在 spring cloud 全家桶中配置中心使用的是 spring-cloud-config 包,其提供了配置拉取服务,然而并没有提供配置管理能力,而是通过插件来进行管理;例如,git 等;所以大体的架构图如下:


从这个图来看,感觉 config-server 没体现出它的价值。之所以需要 config-server 这个存在,主要考虑几个点,也是官方所列出来的特性:

  • 提供 http 协议的请求方式

  • 对元数据进行加密解密

  • 更好的集成到 spring boot 应用

如果客户端在运行当中,git 的配置发生了变更了,想要达到客户端拿到变更后的数据,则需要额外的组件来配置,官方提供的建议是使用 spring-cloud-bus 以及 spring-config-monitor 来配合。具体的交互如下图:

至于加密的,则在使用以及源码层面解读时进行介绍。

二. 原理

2.1 服务端

当服务端启动时,对配置内容解析有两种方式:

  • 饿汉模式,即立即将配置资源加载到服务端内部;

  • 懒汉模式,由客户端要拉取时,才加载到服务端内部;

其配置资源数据结构 org.springframework.cloud.config.environment.Environment 是:

即意味着服务端是基于这个最小数据维度进行管理配置信息;

2.2 客户端

当客户端启动时,向服务端拉取配置信息,即上面的 Environment 信息,然后加载到客户端的环境变量中,供使用;

2.3 总结

配置中心平台相对交互简单,服务端对配置进行管理;客户端向服务端拉取配置信息;


三. spring-cloud-config 实现原理

在 spring boot2.6.*版本,是使用 EnvironmentPostProcessor 接口所对应的实现 ConfigDataEnvironmentPostProcessor 类来实现;

而一旦配置发生了变更,通过事件形式去触发,最终会调用类去重新刷新配置。

  • 服务端主要是 ConfigDataEnvironmentPostProcessor 类来处理

  • 客户端主要是 ConfigFileApplicationListener 类向

该接口的实现类主要是对 spring environment 对象进行前置,例如往里面增加额外的环境变量,以及修改环境变量等操作;那么什么时候会被出发呢?主要是由事件监听等方式去触发,例如 spring boot 启动时会抛出 ApplicationEnvironmentPreparedEvent 事件。

2.1 服务端

其底层原理是运用了 EnvironmentRepository 接口来获取对应的配置信息,从而实现多样化的配置中心;

2.1.1 配置管理

当我们直接引用 jar,如下代码。默认是使用的 git 进行管理配置;

<dependency>	<groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-config-server</artifactId></dependency>
复制代码

所以,config-server 本身是不提供配置管理的。

我们可以在配置文件中配置 git 地址即可;具体都配置哪些内容,可查阅 MultipleJGitEnvironmentProperties 类即可;这里可以配置多个 git 地址。

当容器启动时会向 git 仓库拉取文件到本地,具体流程如下:

2.1.2 http 服务

所提供的服务能力,主要可以查阅三个类

  • EncryptionController 提供加密解密服务

  • EnvironmentController 提供了获取对应的以 Environment 类承载的配置信息对象

  • ResourceController 提供了获取对应的以字符串类承载的配置信息对象

下面以当 EnvironmentController 类的接收到客户端向服务端拉取配置请求的大体流程如下:

这里重点介绍匹配到对应的 git 仓库以及对应的目录规则;

  1. 匹配 git 仓库:将配置的 git url 中的{application}、{profile}、{label}关键进行替换成对应值,得到的才是真正的 git 仓库地址;

  2. 获取到对应目录:假设 git 仓库拉取到本地的路径,/data/git/config

  3. 如果我们配置了 searchPath 值,则会尝试替换{application}、{profile}、{label}得到 git 拉到本地下的最终的目录。假设是 application/profile/label 这个目录,那么最终的目录是/data/git/config/application/profile/label/

  4. 如果没有配置,则默认是/data/git/config,那么最终的目录是/data/git/config

这里面的流程有点复杂,尤其是 ConfigDataEnvironmentPostProcessor 工具对 ConfigurableEnvironment 对象中的是 spring.config.name,spring.config.location 等所指定的路径。但是不难可以猜测的出,其最终会流转到 ConfigDataLocationResolver 接口所对应的实现类去拉取文件资源,流程图如下:

上面的流程图,只是关键的流程,不涉及很多细节;从上面的流程图,还可以再次精简,流程图如下:

这里有一个疑惑点:客户端端每次启动时向配置服务拉取时,都会重新加载解析文件麽?

虽然有点概览了,但是细节不能一一阐述到位,就举个场景来说明:


2.1.3 解密

其通过对 EnvironmentEncryptor 接口的实现类去对属性对象的含有{cipher}前缀的 value 进行解密;

具体可以查看 CipherEnvironmentEncryptor 对象;逻辑都很清晰;

2.1.4 配置实时性

这里主要是讲述的是一旦 git 仓库中的配置发生了变更,那么 config-server 中的配置就会发生变更;然而这个实时性是懒加载模式,有客户端主动拉取时,config-server 才会重新向 git 仓库拉取地址;

这里主要是依赖 spring cloud 中的 @RefreshScope 注解的功能特性;但是我们需要添加额外的依赖包,如下:

 <dependency> 	<groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-config-monitor</artifactId> </dependency>
复制代码

然后在 git 中添加 webhook,url 如下:

${spring.cloud.config.monitor.endpoint.path:}/monitor
复制代码

当 git 回调告知配置已经变更时,就会抛出 RefreshRemoteApplicationEvent 事件:会有一个监听器监听并做其对应的处理逻辑,流程图如下:

EnvironmentPostProcessor 接口的实现类很多,这里主要对一些关键类进行简单说明:

  • ConfigFileApplicationListener 加载本地 spring.config.location 等指定的配置文件信息

  • ConfigDataEnvironmentPostProcessor 加载 ConfigData 配置资源到 Environment 对象中去,这一块可以参考上面几个流程图;

  • DecryptEnvironmentPostProcessor 对 environment 加密的配置信息进行解密

2.2 客户端

客户端则直接引入一下 jar 包,即可向服务端拉取配置信息:

<dependency>	<groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-config</artifactId></dependency>
复制代码

当容器启动时,会触发调用 ConfigServicePropertySourceLocator 对象去向 config-server 拉取配置信息;

  • 配置实时性

需要额外引入总线

<dependency>	<groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-bus</artifactId></dependency>
复制代码

这样子才能监听到 config-server 抛出来的刷新 RefreshRemoteApplicationEvent,具体细节可以查看服务端的【配置实时性】小节内容;

三. 架构

配置中心,一般情况只有在服务启动时,以及配置变更时,让客户端重新拉取配置;所以,在大部分时间里是没有被调用的;在做搭建配置中心时,一般主要考虑流量激增场景,是否能承载的住;而不用考虑其高可用性;

默认的 spring cloud config server 使用的 git server,其瓶颈点主要是在 git server;当有上万台微服务启动时,会大量的流量流到 git server 服务器,很容易 git server 出现宕机现象;那么就会出现客户端系统启动失败;

所以要想达到一个稳定的环境,则进行一定的优化,例如,

  • 取消定时先 git server 拉取最新配置等;

  • 增加缓存特性,减少对 git 的访问;那么意味着需要添加代码才能达到该特性,目前源码中是没有实现该特性的;

  • config-server 启动时,直接拉取 git 仓库到服务端所在的文件服务系统中;

针对该 spring-cloud-config 的个人想法:

  • 局限性:

  • 配置实时性,依赖的内容太多,引入总线,以及总线对应的 MQ;以及 git 的 webhook。

  • 缺少缓存特性

  • 高并发低效

  • 优化想法:

  • 将配置仓库与配置管理完全独立化,增加配置同步模块

配置仓库,可以往里面增加缓存特性。当配置同步模块中发现有信息变更时。会通知到配置仓库,让配置仓库模块修改对应的变更内容;

客户端,在启动时会向服务端拉取配置信息。同时起一个定时任务,定时向服务端发送询问,配置是否发生了变更,一旦发生了变更,则重新拉取配置信息,并替换当前的配置内容;

四. 使用

4.1 服务端

application.yml

server:  port: 8888 #设置端口spring:  application:    name: config-server #设置名称  cloud:    config:      server:        git:          uri: https://gitee.com/******/{application}.git #设置git仓库地址          force-pull: false #设置强行pull拉取          searchPaths:            - application-{profile}          username: ****          password: ****
复制代码

4.2 客户端

bootstrap.yml

server:  port: ****spring:  profiles:    active: sit  application:    name: 应用名称  cloud:    config:      uri:       - http:配置中心地址
复制代码


发布于: 刚刚阅读数: 2
用户头像

邱学喆

关注

计算机原理的深度解读,源码分析。 2018.08.26 加入

在IT领域keep Learning。要知其然,也要知其所以然。原理的爱好,源码的阅读。输出我对原理以及源码解读的理解。个人的仓库:https://gitee.com/Michael_Chan

评论

发布
暂无评论
spring cloud篇之配置中心_加密解密_邱学喆_InfoQ写作平台