分布式配置中心介绍--Spring Cloud学习第六天
文章大纲
一、分布式配置中心是什么
二、配置基本实现
三、spring cloud config服务端配置细节(一)
四、spring cloud config服务端配置细节(二)
五、spring cloud config客户端配置细节
六、项目源码与参考资料下载
七、参考文章
一、分布式配置中心是什么
随着我们的分布式项目越来越大,我们可能需要将配置文件抽取出来单独管理,spring cloud config对这种需求提供了支持。spring cloud config为分布式系统中的外部配置提供服务器和客户端支持。我们可以使用config server在所有环境中管理应用程序的外部属性,config server也称为分布式配置中心,本质上它就是一个独立的微服务应用,用来连接配置仓库并将获取到的配置信息提供给客户端使用;客户端就是我们的各个微服务应用,我们在客户端上指定配置中心的位置,客户端在启动的时候就会自动去从配置中心获取和加载配置信息。spring cloud config可以与任何语言运行的应用程序一起使用。服务器存储后端的默认实现使用git,因此它轻松支持配置信息的版本管理,当然我们也可以使用git客户端工具来管理配置信息。本文我们就先来看下spring cloud config的一个基本使用。
二、配置基本实现
1. 构建配置中心
首先我们来构建一个配置中心,方式很简单,创建一个普通的spring boot项目,叫做config-server,创建好之后,添加如下依赖:
<parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.5.7.release</version> <relativepath/> <!-- lookup parent from repository --> </parent> <properties> <spring-cloud.version>dalston.sr3</spring-cloud.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-config-server</artifactid> </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>
然后在入口类上添加@enableconfigserver注解,表示开启配置中心服务端功能,如下:
@springbootapplication @enableconfigserver public class configserverapplication { public static void main(string[] args) { springapplication.run(configserverapplication.class, args); } }
然后在application.properties中配置一下git仓库的信息,为了简单,我这里就不自己搭建git服务端了,直接使用github(当然也可以使用码云),这里需要我首先在我的github上创建一个名为scconfig的项目,创建好之后,再做如下配置:
spring.application.name=config-server server.port=2007 spring.cloud.config.server.git.uri=https://github.com/lenve/scconfig.git spring.cloud.config.server.git.search-paths=config-repo spring.cloud.config.server.git.username=username spring.cloud.config.server.git.password=password
前两行配置的含义就不用我多说了,我说下后面四行配置的含义,如下:
(1)uri表示配置中心所在仓库的位置
(2)search-paths表示仓库下的子目录
(3)username表示你的github用户名
(4)password表示你的github密码
做好这些之后我们的配置中心服务端就创建好了。
2. 构建配置仓库
接下来我们需要在github上设置好配置中心,首先我在本地找一个空文件夹,在该文件夹中创建一个文件夹叫config-repo,然后在config-repo中创建四个配置文件,如下:
四个文件中的内容分别如下:
ok,然后回到test目录下,依次执行如下命令将本地文件同步到github仓库中,如下:
如此之后,我们的配置文件就上传到github上了。此时启动我们的配置中心,通过/{application}/{profile}/{label}就能访问到我们的配置文件了,其中application表示配置文件的名字,对应我们上面的配置文件就是app,profile表示环境,我们有dev、test、prod还有默认,label表示分支,默认我们都是放在master分支上,我们在浏览器*问结果如下:
ok,从这里我们看到了我们放在仓库中的配置文件。json中的name表示配置文件名application的部分,profiles表示环境部分,label表示分支,多了一个version,实际上就是我们github上提交信息时产生的版本号,当我们访问成功后,我们还可以看到控制台打印了如下日志:
实际上是配置中心通过git clone命令将配置文件在本地保存了一份,这样可以确保在git仓库挂掉的时候我们的应用还可以继续运行,此时我们断掉网络,再访问http://localhost:2007/app/prod/master,一样还可以拿到数据,此时的数据就是从本地获取的。
3. 客户端配置
服务端搞好了,接下来我们来看看怎么样在客户端使用。
首先创建一个普通的spring boot工程config-client,创建成功之后添加如下依赖:
<parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.5.7.release</version> <relativepath/> <!-- lookup parent from repository --> </parent> <properties> <spring-cloud.version>dalston.sr3</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> </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>
然后创建bootstrap.properties文件,来获取配置信息,注意这些信息一定要放在bootstrap.properties文件中才有效,文件内容如下:
spring.application.name=app spring.cloud.config.profile=dev spring.cloud.config.label=master spring.cloud.config.uri=http://localhost:2007/ server.port=2008
这里的name对应了配置文件中的application部分,profile对应了profile部分,label对应了label部分,uri则表示配置中心的地址。配置完成之后创建一个测试controller,我们来看看效果:
@restcontroller @refreshscope public class hellocontroller { @value("${sang}") string sang; @autowired environment env; @requestmapping("/sang") public string sang() { return this.sang; } @requestmapping("/sang2") public string sang2() { return env.getproperty("sang", "未定义"); } }
我们可以直接注入值,也可以通过environment来获取值,访问结果如下:
三、spring cloud config服务端配置细节(一)
我们先通过下面一张图来看看config server的一个大致工作过程:
说明
1.首先我们需要一个远程的git仓库,自己学习可以直接用github,在在实际生产环境中,需要自己搭建一个git服务器,远程git仓库的作用主要是用来保存我们的配置文件
2.除了远程git仓库之外,我们还需要一个本地git仓库,每当config server访问远程git仓库时,都会保存一份到本地,这样当远程仓库无法连接时,就直接使用本地存储的配置信息
3.至于微服务a、微服务b则是我们具体的应用,这些应用在启动的时候会从config server中来加载相应的配置信息
4.当微服务a/b尝试去从config server中加载配置信息的时候,config server会先通过git clone命令克隆一份配置文件保存到本地
5.由于配置文件是存储在git仓库中,所以配置文件天然的具备版本管理功能,git中的hook功能可以实时监控配置文件的修改
git uri中的占位符
灵活的使用uri占位符,可以有效的减少我们的工作量。考虑这样一个问题,我有servera、serverb两个服务,两个服务对应的配置文件的存储地址分别位于https://github.com/lenve/scconfig/sa和https://github.com/lenve/scconfig/sb,但是我的config server只有一个,那么当我的servera和serverb连接上config server时,config server怎么知道去哪个地址下拿配置文件?这个时候就涉及到占位符的使用。
在上篇文章中我们已经了解了spring cloud config中的三种占位符,分别是{application}、{profile}和{label},这些占位符除了用来标识配置文件的规则,还可以用在config server中对git仓库的uri配置,用在uri配置中时,这三个占位符的含义分别如下所示:
1.{application}映射到客户端的 spring.application.name
2.{profile}映射到客户端上的 spring.profiles.active
3.{label}这是一个服务器端功能,标记”版本”的配置文件集
此时,假设我不同环境下的配置文件分别放在下面这些目录下:
https://github.com/lenve/scconfig/app/dev https://github.com/lenve/scconfig/app/prod https://github.com/lenve/scconfig/app/test
那么我的客户端文件这样配置:
spring.application.name=app # dev根据具体情况来修改 spring.cloud.config.profile=dev spring.cloud.config.label=master spring.cloud.config.uri=http://localhost:2007/ server.port=2008
然后config server按下面这种方式配置即可:
spring.cloud.config.server.git.uri=https://github.com/lenve/scconfig.git spring.cloud.config.server.git.search-paths={application}/{profile}
当然这种存储规划不一定最佳,这里只是给小伙伴们演示占位符的用法。
默认情况下,config server 克隆下来的文件保存在c:\users<当前用户>\appdata\local\temp目录下,我们可以通过如下配置来修改:
spring.cloud.config.server.git.basedir=e:\\111\\
健康监测
默认情况下spring cloud config会为配置中心服务端创建一个健康监测器,该检测器默认情况下是访问的仓库文件是{application}为app的配置文件,如果仓库中不存在这个文件,健康显示器就会显示仓库无法连接,此时我们有两种解决方案:1.仓库中添加相应的配置文件;2.重新指定检测的配置,重新指定方式如下:
spring.cloud.config.server.health.repositories.check.name=app spring.cloud.config.server.health.repositories.check.label=master spring.cloud.config.server.health.repositories.check.profiles=dev
此时,系统回去访问http://localhost:2007/app/dev/master地址,如果能够访问到,则显示仓库已连接,如下:
安全保护
开发环境中我们的配置中心肯定是不能随随便便被人访问的,我们可以加上适当的保护机制,由于微服务是构建在spring boot之上,所以整合spring security是最方便的方式。
首先添加依赖:
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency>
然后在application.properties中配置用户名密码:
security.user.name=sang security.user.password=123
最后在配置中心的客户端上配置用户名和密码即可,如下:
spring.cloud.config.username=sang spring.cloud.config.password=123
四、spring cloud config服务端配置细节(二)
1. 简介
在微服务架构中,由于独立的服务个数众多,加上前期测试工作量大,一些原本由运维人员维护的敏感信息会被我们直接写在微服务中,以提高开发效率,但是这种明文存储方式显然是非常危险的,所以我们要对这些信息进行加密,而spring cloud config则提供了对称加解密、非对称加解密的功能来帮助我们完成这一需求。ok,本文我们就来看看如何实现配置信息的加解密。
2. 准备工作
默认情况下我们的jre中自带了jce(java cryptography extension),但是默认是一个有限长度的版本,我们这里需要一个不限长度的jce,这个jce我们可以直接百度然后在oracle官网下载,下载之后解压,我们可以看到如下三个文件:
我们需要将这里的两个jar包拷贝到我们的jdk安装目录下,我的是%java_home%\jre\lib\security
,覆盖该目录下原有的文件。
如此之后,我们的准备工作就完成了。
3. 对称加解密
对称加解密比较简单,直接配置密钥就可以了,在我们前文创建出来的config-server中配置密钥,但是注意这个密钥需要配置在bootstrap.properties中,另外这里还有非常重要一点:spring cloud的dalston.sr3和dalston.sr2版本在这个问题上是有bug的,如果用这两个版本在这里测试会没有效果,应该避开使用这两个版本,我这里使用的是dalston.sr4版本,配置如下:
encrypt.key=sang
配置完成之后,启动我们的config-server工程,然后访问如下地址http://localhost:2007/encrypt/status,如果看到如下访问结果,表示环境搭建成功了:
此时我们就可以通过第三方工具如postman、restclient等来访问/encrypt和/decrypt接口,比如说我要给dev这个字符加密,方式如下(我这里以postman为例,注意是post请求):
解密方式如下:
ok,拿到加密的字符串之后,我们就可以在配置文件中使用了,还是我们昨天的配置文件,这次我这样来写:
小伙伴们注意,配置文件的值如果是以{cipher}
开头,表示该值是一个加密字符,配置中心config-server在获取到这个值之后会先对值进行解密,解密之后才会返回给客户端使用。
4. 非对称加解密
上文我们使用了对称加解密的方式来确保配置文件的安全性,如果使用非对称加解密的方式,我们的安全性将会得到进一步的提高。使用非对称加密的话需要我们先生成密钥对,生成密钥对可以直接使用jdk中自带的keytool工具,方式如下:
keytool -genkeypair -alias config-server -keyalg rsa -keystore config-server.keystore
执行效果如图:
执行成功之后,会在命令执行目录下生成一个名为config-server.keystore的文件,将该文件拷贝到config-server的src\main\resources目录下,然后做如下配置:
encrypt.key-store.location=config-server.keystore encrypt.key-store.alias=config-server encrypt.key-store.password=111111 encrypt.key-store.secret=111111
ok,如此之后我们的非对称加密就配置好了,测试方式和对称加密的测试方式一致,我这里就不再演示了。
五、spring cloud config客户端配置细节
服务化配置中心
在前面几篇关于spring cloud config配置中心的文章中,我们在config-client中配置config-server地址的时候都是直接将地址写死,这种方式显然不够灵活,有的小伙伴可能已经想到了,这里我们可以结合eureka注册中心,然后在配置的时候直接使用服务名即可,ok,那我们对之前的项目稍加改造吧。
config-server改造
这里的改造都是非常简单的,服务端改造和客户端改造都是分三步走:1.添加依赖;2.添加注解;3.修改application.properties.
首先我们在config-server中添加如下依赖:
<dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-eureka</artifactid> </dependency>
然后在config-server的入口类上添加@enablediscoveryclient注解,表示这是一个eureka客户端,如下:
@springbootapplication @enableconfigserver @enablediscoveryclient public class configserverapplication { public static void main(string[] args) { springapplication.run(configserverapplication.class, args); } }
最后在application.properties中配置eureka注册中心地址:
eureka.client.service-url.defaultzone=http://localhost:1111/eureka/
至此,我们的config-server就配置成功了。
config-client改造
config-client改造第一步也是先添加依赖,如下:
<dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-eureka</artifactid> </dependency>
然后入口类添加@enablediscoveryclient注解,如下:
@springbootapplication @enablediscoveryclient public class configclientapplication { public static void main(string[] args) { springapplication.run(configclientapplication.class, args); } }
最后修改配置文件,如下:
spring.application.name=app # dev根据具体情况来修改 spring.cloud.config.profile=dev spring.cloud.config.label=master eureka.client.service-url.defaultzone=http://localhost:1111/eureka/ spring.cloud.config.discovery.enabled=true spring.cloud.config.discovery.service-id=config-server server.port=2008
关于这个配置文件我说如下三点:
1.eureka.client.service-url.defaultzone设置了注册中心的地址,将config-client注册到eureka注册中心中去
2.spring.cloud.config.discovery.enabled表示开启通过服务名来访问config-server
3.spring.cloud.config.discovery.service-id=config-server则表示config-server的服务名
测试
ok,经过以上的改造之后,此时我们分别启动eureka服务注册中心、config-server、config-client,然后访问http://localhost:1111,可以看到两个应用都已经注册成功了:
然后继续测试config-client的/sang接口,结果如下:
没问题。
好了,服务化配置中心构建成功。
失败快速响应
不作任何额外配置的情况下,失败响应有点迟钝,举个简单的例子,关掉config-server,我们直接启动config-client,此时启动会报错,但是报错时间较晚,报错的时候系统已经打印了许多启动日志了,如果我们希望在启动失败时能够快速响应,方式很简单,config-client中添加如下配置即可:
spring.cloud.config.fail-fast=true
此时不启动config-server直接启动config-client依然会报错,但是我们看到报错时间较早,系统都没打印几条启动日志。
重试机制
如果由于网络抖动等原因导致config-client在启动时候访问config-server没有访问成功从而报错,这显然是不划算的,遇到这种情况我们希望config-client最好能重试几次,重试机制在这里也是受支持的,添加重试机制的方式很简单,引入如下两个依赖:
<dependency> <groupid>org.springframework.retry</groupid> <artifactid>spring-retry</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-aop</artifactid> </dependency>
引入依赖就ok了,不用做任何额外配置(当然要确保失败快速响应已开启),此时我们再尝试不启动config-server直接启动config-client,得到的启动日志如下:
我们看到,config-client一共尝试了六次去访问config-server,六次都失败了才抛异常。
和重试机制相关的配置有如下四个:
# 配置重试次数,默认为6 spring.cloud.config.retry.max-attempts=6 # 间隔乘数,默认1.1 spring.cloud.config.retry.multiplier=1.1 # 初始重试间隔时间,默认1000ms spring.cloud.config.retry.initial-interval=1000 # 最大间隔时间,默认2000ms spring.cloud.config.retry.max-interval=2000
动态刷新配置
有的时候,我动态的更新了git仓库中的配置文件,那么我如何让我的config-client能够及时感知到呢?方式很简单,首先在config-client中添加如下依赖:
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-actuator</artifactid> </dependency>
该依赖中包含了/refresh端点的实现,我们将利用这个端点来刷新配置信息。然后需要在application.properties中配置忽略权限拦截:
management.security.enabled=false
ok,配置好之后,启动eureka注册中心,config-server和config-client,访问http://localhost:2008/sang,结果如下:
此时我利用git客户端工具,将app-dev.properties中的内容修改一下,修改成功之后,先用post请求访问http://localhost:2008/refresh地址,结果如下:
然后再访问http://localhost:2008/sang,结果如下:
我们看到配置文件已经更新了。
六、项目源码与参考资料下载
链接:https://pan.baidu.com/s/1wga85exfsqqlu7ek1rvf6w
提取码:p7qn
七、参考文章
上一篇: Spring Cloud学习总结
下一篇: ssh远程登录故障解决方案
推荐阅读
-
spring cloud 入门系列七:基于Git存储的分布式配置中心--Spring Cloud Config
-
Spring Cloud 之分布式配置中心--Config
-
SpringCloud学习笔记(7):使用Spring Cloud Config配置中心
-
SpringCloud实战(六)-高可用的分布式配置中心(Spring Cloud Config)
-
SpringCloud教程 | 第11篇:分布式配置中心(Spring Cloud Config) 客户端实战
-
微服务解决方案 -- Spring Cloud Alibaba (五)分布式配置中心
-
分布式配置中心介绍--Spring Cloud学习第六天
-
Spring Cloud(十)高可用的分布式配置中心 Spring Cloud Config 中使用 Refresh
-
《Spring Cloud 入门》Spring Cloud Config 基于JDBC 的分布式配置中心
-
Spring Cloud(八)高可用的分布式配置中心 Spring Cloud Config