大家好,又见面了,我是你们的朋友全栈君。
目录
注:主要只做理论性的总结与分析,相关实战代码会在后面的博客中和github中逐步增加。
一、配置中心的由来及选择
(一)配置中心由来
(二)配置中心要求具备的功能
(三)配置中心基本流转图和支撑体系分析
(四)多种配置中心的选择与对比方案
二、Spring Cloud Config概述及基本实现方法介绍
三、Spring Cloud Config结合Git实现配置中心方案
(一)Git版基本工作原理(未加Spring Cloud Bus热刷新)
(二)Git多种配置信息讲解
(三)基本的手动刷新和结合Spring Cloud Bus热刷新
四、Spring Cloud Config结合关系型数据库MYSQL实现配置中心方案
(一)基本实现原理
(二)基本要求讲解
五、Spring Cloud Config结合非关系性数据库MongoDB实现配置中心方案
(一)基本实现原理
(二)基本要求讲解
六、Spring Cloud Config使用技能及功能扩展
(一)基本实用技能:本地参数覆盖远程参数
(二)客户端自动刷新实现
(三)客户端回退功能实现
(四)客户端安全认证机制JWT实现
七、Spring Cloud Config实现客户端及服务端高可用方案
(一)客户端高可用原理及方案
(二)服务端高可用原理及方案
八、Spring Cloud Config与Apollo配置使用实现界面化操作
(一)Apollo基本概述及基本功能介绍
(二)Apollo总体架构模块分析
(三)Apollo客户端设计与运行环境介绍
参考书籍、文献和资料:
互联网时代下的分布式系统,应用部署在N台服务器上或在云化环境以多实例呈现,如果一个实例一个实例(或一台服务器一台服务器)进行修改配置和重启,一是维护成本极高,二是不现实,配置中心的思想便应运而生。配置中心用作集中管理不同环境和不同集群配置,以及在修改配置后实时动态推送到应用动态更新。
配置中心管理作为微服务六大实现技术之一,从模型上来分析,包括4大分类、4个核心需求和2个维度分析,在分布式下配置中心在实现上需要满足3大需求:高效获取、实时感知、分布式访问。基本理论在之前博客中已经讲解过,具体见以下博客链接:https://blog.csdn.net/xiaofeng10330111/article/details/85682513。
配置中心应该剧本具备以下基本功能,具体如图:
这里只展示了基本的实现功能,从功能特性、技术路线、可用性和易用性方面还有更多的功能要求,具体可以见(四)以及对应的配置中心实现方案对比。
具体可如图所示:
具体对比分类 | 具体对比项 | 重要程度 | Spring Cloud Config | Netflix Archaius | Ctrip Apollo | DisConf |
---|---|---|---|---|---|---|
功能特性 | 静态配置管理 | 高 | 基于file | 无 | 支持 | 支持 |
动态配置管理 | 高 | 支持 | 支持 | 支持 | 支持 | |
统一管理 | 高 | 无,需要git、数据库等 | 无 | 支持 | 支持 | |
多维度管理 | 中 | 无,需要git、数据库等 | 无 | 支持 | 支持 | |
变更管理 | 高 | 无,需要git、数据库等 | 无 | 无 | 无 | |
本地配置缓存 | 高 | 无 | 无 | 支持 | 支持 | |
配置更新策略 | 中 | 无 | 无 | 无 | 无 | |
配置锁 | 中 | 支持 | 不支持 | 不支持 | 不支持 | |
配置校验 | 中 | 无 | 无 | 无 | 无 | |
配置生效时间 | 高 | 重启生效,手动刷新 | 手动刷新生效 | 实时 | 实时 | |
配置更新推送 | 高 | 需要手动触发 | 需要手动触发 | 支持 | 支持 | |
配置定时拉取 | 高 | 无 | 无 | 支持 | 配置更新目前依赖事件驱动,client重启或server推送操作 | |
用户权限管理 | 中 | 无,需要git、数据库等 | 无 | 支持 | 支持 | |
授权、审核、审计 | 中 | 无,需要git、数据库等 | 无 | 界面直接提供发布历史和回滚按钮 | 操作记录有赖数据库,但无查询接口 | |
配置版本管理 | 高 | git | 无 | 支持 | 无,需要git、数据库等 | |
配置合规检测 | 高 | 不支持 | 不支持 | 支持(还需完善) | ||
实例配置监控 | 高 | 需要结合Spring Admin | 不支持 | 支持 | 支持,可以查看每个配置在哪台机器上加载 | |
灰度发布 | 中 | 不支持 | 不支持 | 支持 | 不支持部分更新 | |
告警通知 | 中 | 不支持 | 不支持 | 支持邮件方式告警 | 支持邮件方式告警 | |
统计报表 | 中 | 不支持 | 不支持 | 不支持 | 不支持 | |
依赖关系 | 高 | 不支持 | 不支持 | 不支持 | 不支持 | |
技术路线 | 支持Spring Boot | 高 | 原生支持 | 低 | 支持 | 与Spring Boot无关 |
支持Spring Config | 高 | 原生支持 | 低 | 支持 | 与Spring Cloud无关 | |
客户端支持 | 低 | java | java | java、.net | java | |
业务系统入侵性 | 高 | 入侵性弱 | 入侵性弱 | 入侵性弱 | 入侵性弱,支持注解和xml | |
可依赖组件 | 高 | |||||
可用性 | 单点故障(SPOF) | 高 | 支持HA部署 | 支持HA部署 | 支持HA部署 | 支持HA部署,高可用由ZK提供 |
多数据中心部署 | 高 | 支持 | 支持 | 支持 | 支持 | |
配置获取性能 | 高 | unkown | unkown | unkown | unkown | |
易用性 | 配置界面 | 中 | 无,需要git、数据库等操作 | 无 | 统一界面 | 统一界面 |
结论:
我们主要对Spring Cloud Config进行分析和理解,Apollo做辅助分析,关于Apollo的相关知识有时间在进行学习和分享。
Spring Cloud Config是Spring Cloud微服务体系中的配置中心,是一个集中化外部配置的分布式系统,由服务端和客户端组成,其不依赖于注册中心,是一个独立的配置中心,支持多种存储配置信息形式,目前主要有jdbc、value、native、svn、git,其中默认是git。重点讨论功能有如下两个方面:
因为采用native方式必然决定了每次配置完相关文件后一定要重启Spring Cloud Config,所以一般我们不会采用此方案,在实际操作中我们主要的实现方案有以下四种:Spring Cloud Config结合Git实现配置中心方案+Spring Cloud Config结合关系型数据库实现配置中心方案+Spring Cloud Config结合非关系型数据库实现配置中心方案+Spring Cloud Config与Apollo配置结合实现界面化配置中心方案。
配置客户端启动时会向服务器发起请求,服务端接收到客户端的请求后,根据配置的仓库地址将Git上的文件克隆到本地的一个临时目录中,这个目录是一个Git的本地仓库目录,然后服务端再读取本地文件返回给客户端。这样做的好处是,当Git服务器故障或者网络请求异常时,保证服务端仍然可以正常工作。
在实际实现上,服务端需要配置好git的uri地址信息以及search-paths信息,并在对应Git中与之相对应,客户端在bootstrap文件中按照其内容和具体文件名进行配置label、uri、name、profile等消息即可,但是在基本实现上如果修改文件后依旧需要重启来解决此问题,所以需要进行手动刷新或结合Spring Cloud Bus进行热刷新。
关于Git配置信息而言,其主要有以下几种方式:
Spring Cloud Config默认使用Git,对Git的配置也最简单,Config Server可用uri、username、password这三个参数就可以读取配置了,通过Git的版本控制可以使Config Server适应特殊的场景。
测试时我们也可以使用本地仓库的方式,使用file://
前缀,那么uri的配置就可以写作
spring:
cloud:
config:
server:
git:
uri: file://${user.home}/config-repo #注意:Windows系统需要使用file:///前缀
# ${user.home}代表当前用户的家目录
Spring Cloud Config Server支持占位符的使用,支持{application}
、{profile}
、{label}
这些占位符对Git的uri配置,通过占位符使用应用名称来区分应用对应的仓库然后进行使用。这里需要注意仓库名称和仓库下面的配置文件名称一致才可以,因为配置了spring.cloud.config.name默认占位符匹配的是spring.application.name。
spring:
cloud:
config:
server:
git:
uri: https://github.com/hellxz/SpringCloudlearn/config-repo/{application}
#此时spring.application.name的值会填充到这个uri中,从而达到动态获取不同位置的配置
Spring Cloud Config Server除了使用{应用名}/{环境名}
来匹配配置仓库外,还支持通过带有通配符的表达式来匹配。
当有多个匹配规则的时候,可以用逗号分隔多个{应用名}/{环境名}
配置规则。以官方文档例子举例:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo #默认的仓库
#注意:配置多个仓库时,Config Server 在启动时会直接克隆第一个仓库的配置库,其他配置库只有请求时才会clone到本地
repos:
simple: https://github.com/simple/config-repo
special:
pattern: special*/dev*,*special*/dev*
uri: https://github.com/special/config-repo
local:
pattern: local*
uri: file:/home/configsvc/config-repo
test:
pattern:
- '*/development'
- '*/staging'
uri: https://github.com/development/config-repo
如果{应用名}/{环境名}
不能匹配到仓库,那么就在默认的uri下去查找配置文件。
上边的例子中,
simple/*
local*/*
通过spring.cloud.config.server.git.searchPaths
来定位到Git仓库的子目录中,相当于在uri后加上searchPaths的目录。
searchPaths参数的配置也支持使用{应用名}、{环境名}、{分支名}占位符,比如spring.cloud.config.server.git.searchPaths={应用名}
,通过这样的配置,我们能让每一个应用匹配到自己的目录中。如下举例:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
searchPaths: '{application}'
使用Git仓库的时候,使用HTTP认证需要使用username和password属性来配置账户,具体如下:
(还可以使用SSH认证,Config Server本地的.ssh文件或使用私钥等进行配置,如:http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_git_ssh_configuration_using_properties)
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
username: trolley
password: strongpassword
为了避免重启项目才能获取最新的配置信息,可以进一步优化做到手动刷新和结合Spring Cloud Bus进行热刷新,其基本要求一般不改动服务端相关配置和代码,但是需要各客户端增加断点访问依赖和安全依赖,这样就可以对外通过访问客户端刷新断点uri来进行刷新操作,手动刷新就是直接访问断点的方式,虽然简单,但是如果每次都要手动刷新的话,面对微服务很多的情况下,就会因为操作人员忘记或者遗漏的情况,从而造成服务出错。在生产实践中,我们往往要求结合Spring Cloud Bus进行热刷新。
结合Spring Cloud Bus进行热刷新的操作如上图所示,用户更新配置信息时,检查到Git Hook变化,触发Hook配置地址的调用,Config Server接收到请求并发布消息,Bus将消息发送到Config Client,当Config Client接收到消息后重新发送请求加载配置消息。
Spring Cloud Config是一个独立的配置中心,支持多种存储配置信息形式,其中包括jdbc方式,其基本原理图如下:
git有它天然的优势,比如多版本管理、分支管理、提交审核策略等等,但是如果相对其中存储的数据做细粒度的权限控制,就力不从心了。我们可以将持久化从git迁移到MySQL上,这样的好处就是,可以针对配置中心,方便开发出一些对外接口,例如一些用户可配置的动态改更新的参数,同时,由于是数据库方式,当让可以自己在此基础上实现视图化和刷新机制,整体上显得更加优雅。
具体实现上,需要Config Server端增加服务中心jar包、-配置中心jar包、连接msql数据库相关jar包这三个必须的jar包,在配置文件中需要增加对应的服务名称、连接配置信息、mysql 属性配置、指定注册中心地址等,具体我们要分析的是连接配置信息:
#连接配置信息
spring:
application:
name: config-server-jdbc
profiles:
active: jdbc
cloud:
config:
server:
default-label: dev
jdbc:
sql: SELECT akey , avalue FROM config_server where APPLICATION=? and APROFILE=? and LABEL=?
连接配置信息中:
key
、value
是保留关键词,原生的实现语句会报错,所以需要重写一下这句查询语句(如果存储的表结构设计不同于上面准备的内容,也可以通过这个属性的配置来修改配置的获取逻辑)然后便是启动类等注解配置和数据库相关操作与构建,相关代码具体见后面博客及github。
注意,JDBC存储的使用思路,具体使用实际上还有很多可以优化的空间,比如:索引的优化、查询语句的优化;如果还需要进一步定制管理,对于表结构的优化也是很有必要的。
Spring Cloud Config作为独立的配置中心,支持多种存储配置信息形式,但是没有提供MongoDB的方式,但是目前已经有相关孵化器,其基本原理图如下:
其基本原理与关系型数据库原理相类似,相关代码具体见后面博客及github。
具体实现上,需要Config Server端增加服务中心jar包、-配置中心jar包、连接mongo数据库相关jar包这三个必须的jar包,在配置文件中需要增加对应的服务名称、连接配置信息、mongo属性配置、指定注册中心地址等,相关代码具体见后面博客及github。
主要是指使用本地的参数覆盖远程的参数,这在开发的时候经常会用到,主要配合内容如下:
spring:
cloud:
config:
allowOverride: true
overrideNone: true
overrideSystemProperties: false
这三个属性的意思是:
在一些应用上面,不需要在服务端批量推送的时候,客户端本身需要获取变化参数的情况,这个时候需要使用客户端自动刷新来完成该功能。具体实现上,可以单独在二方包中增加一个用于自动刷新的功能,引入spring-cloud-config-client和spring-cloud-autoconfigure,并且增加自动配置类(增加间隔刷新时间),在该类中主要注入端点类,通过定时任务和刷新时间,进行配置请求刷新,添加配置后,我们将二方包引入到实际的客户端应用中。
在客户端中需要引入spring-cloud-config-client、spring-boot-starter-security和我们刚刚新做的二方包,并且在对应的配置文件中增加spring.cloud.config.refreshInterval内容,写一个相关的控制器便可以开始测试了,相关代码具体见后面博客及github。
客户端可以匹配回退机制,主要用于以下两种场景,应用回退手段来处理案例:
当启用回退时,客户端适配器将“缓存”本地文件系统中的计算属性。要启用回退功能,只需要指定存储缓存的位置即可。
在具体实现上,我们同样需要在二方包增加对应可以实现客户端回退功能的内容,引入spring-cloud-config-client和spring-security-rsa,增加自动配置类(包含回退本地配置文件所在的文件和名称、要回退配置文件的路径、用来创建本地回退文件的方法)和相关配置内容,
Spring Cloud Config客户端使用JWT身份验证方法代替标准的基本身份验证,这种方式需要对服务端和客户端都要改造,具体如下:
在具体实现上,需要在二方包中引入jwt相关内容,并将该二方包作为基本包使用,在此二方包中pom中必须需要引入一下这三项内容spring-boot-autoconfigure、spring-boot-autoconfiguration-processor、spring-cloud-starter-config,创建Config配置类(引入标示username和password以及endpoint内容,同时增加初始化init并采用注解@PostConstruct,表明在Servelt构造函数和Init()方法之间执行具体容器加载),并进一步创建实体类LoginRequest(对应请求username和password)和实体类Token(对应生成的token)。
将此二方包引入到客户端的pom中,同时引入spring-cloud-config-client,并且在对应bootstrap文件中添加用于参与安全认证所需要的username、password、endpoint(是一个http地址,config server的访问授权地址)。增加启动类和控制器进行测试。
接下来就需要对服务端的代码进行分析和讨论了,首先,需要在pom中引入spring-cloud-config-server、jwt、gson、spring-boot-starter-security,创建JwtAuthenticationRequest类用于传递用户名和密码,创建JwtAuthenticationResponse实体类返回token信息,创建JwtUser用户认证信息实体类,创建JWT的token认证过滤器和JWT工具类(用于生成token和token验证),创建JWT认证端点类(在认证过程中,未能认证通过的直接返回401状态码),接着创建一个认证账号的验证类MemberServiceImpl及将数据封装为json返回客户端的WebAuthenticationDetailsSourceImpl,最后创建Config进行安全和过滤的自动配置类,增加控制器用于测试,相关代码具体见后面博客及github。相关具体类调用时序图如下:
客户端的高可用方式,从方案角度来看,主要还是用file的形式,和前面客户端的回退方案思路大致一样,客户端高可用主要是解决当服务端不可用的情况下,在客户端仍然可以正常启动。从客户端的角度出发,不是增加配置中心的高可用性,而是降低客户端对配置中心的依赖程度,从而提高整个分布式架构的健壮性。
具体实现上,仍然需要创建一个二方包,在二方包中引入spring-cloud-config-client,并且配置属性加载类,创建配置类命名为ConfigSupportConfiguration(主要是用于判断远程加载信息是否可用,如果不能用则将读取加载本地配置文件启动),同时在二方包中增加配置文件spring.factories指明org.springframework.cloud.bootstrap.BootstrapConfiguration。
将该二方包引入对应的客户端的pom中,同时引入spring-cloud-config-client,在bootstrap文件中增加backup开关并指明你备份的本地地址fallbackLocation,增加对应的启动类和控制器用于测试,相关代码具体见后面博客及github。
服务端的高可用在生产环境中也一样重要,通过结合Eureka注册中心的方式来搭建Spring Cloud Config Server高可用,通过Ribbon的负载均衡选择一个Config Server进行连接来获取配置信息,具体流程见上图。
具体实现上,Eureka相关开发与之前是一样的,不用做多余的代码工作;服务端的pom文件中需要引入spring-cloud-config-server和spring-cloud-starter-netflix-eureka-client,其他按照之前的开发即可;客户端的pom文件中需要引入spring-cloud-config-client和spring-cloud-starter-netflix-eureka-client,并且在bootstrap中不在配置spring.cloud.config.uri信息用于指定Server端地址,而是增加了三个新的配置,具体如下:
接着,按照以往的流程测试高可用就可以了,相关代码具体见后面博客及github。
Apollo(阿波罗)是携程框架部研发并开源的一款生产级的配置中心产品,它能够集中管理应用在不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
Apollo目前在国内开发者社区比较热,在Github上有超过5k颗星,在国内众多互联网公司有落地案例,可以说Apollo是目前配置中心产品领域Number1的产品,其成熟度和企业级特性要远远强于Spring Cloud体系中的Spring Cloud Config产品。
Apollo采用分布式微服务架构,它的架构有一点复杂,Apollo的作者宋顺虽然给出了一个架构图,但是如果没有一定的分布式微服务架构基础的话,则普通的开发人员甚至是架构师也很难一下子理解。
总体架构模块如下图所示:
其主要包含了四个核心模块和三个辅助模块:
(ConfigService和AdminService都是多实例无状态的部署,需要将自身注册到Eureka中并保持心跳)
Apollo可以和Spring Cloud Config搭建的微服务进行无缝集成。
有以下几方面的原因:
Apollo客户端的实现原理:
这是一个fallback机制,为了防止推送机制失效导致配置不更新
客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 – Not Modified
定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
Apollo客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。长连接实际上我们是通过Http Long Polling实现的,具体而言:
考虑到会有数万客户端向服务端发起长连,在服务端使用了async servlet(Spring DeferredResult)来服务Http Long Polling请求。
Apllo这部分的内容目前我还没有在实践中应用,所以后续博客和github中可能暂不停工代码分析。
【1】郑天民. 微服务设计原理与架构. 北京:人民邮电出版社,2018.
【2】徐进,叶志远,钟尊发,蔡波斯等. 重新定义Spring Cloud. 北京:机械工业出版社. 2018.
【3】https://blog.csdn.net/xiaofeng10330111/article/details/85682513.
【4】http://blog.sina.com.cn/s/blog_17ea544680102xive.html.
【5】https://www.cnblogs.com/hellxz/p/9306507.html.
【6】https://www.jb51.net/article/147212.htm.
【7】https://blog.csdn.net/hjbbjh0521/article/details/80363947.
【8】http://blog.didispace.com/spring-cloud-starter-edgware-3-1/.
【9】https://blog.csdn.net/john1337/article/details/82413837.
【10】https://blog.csdn.net/zjh_746140129/article/details/86179522.
【11】https://blog.csdn.net/ningjiebing/article/details/90638974.
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/125889.html原文链接:https://javaforall.cn