一文带你吃透Spring Cloud相关微服务组件及Spring Cloud Config框架
Posted jinggege795
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文带你吃透Spring Cloud相关微服务组件及Spring Cloud Config框架相关的知识,希望对你有一定的参考价值。
Spring Cloud相关组件
◎ 统一配置中心
◎ 断路器
◎ 健康监控
◎ 分布式链路跟踪
第2章中介绍了微服务的核心技术及相关的技术实现,服务的远程调用和服务的注册发现是微服务的两大核心架构组件,当有了这两个功能,服务消费者就可以动态地发现和剔除服务提供者,并且可以设置适合的负载均衡策略,灵活地选择需要调用的服务器。这虽然已经可以满足微服务一些基础的日常功能要求,但也没有这么简单,还存在一些如海量服务的容错问题、雪崩问题、配置和监控问题、日志追踪问题等。本章将介绍Spring Cloud的相关微服务组件,以及解决这些问题的方法。
统一配置中心
统一配置中心就是将所有的配置中心化,放在一处来维护,然后通过一定的方法让大家都能读取自己需要的配置信息,一旦有配置需要修改,只需修改配置中心的配置即可,所有依赖该配置信息的服务通过配置中心就能读取到修改后的配置信息。那么,统一配置中心的目的是什么?又会给系统带来哪些便利?
配置中心的难点
设想一下,如果一个应用服务部署了多个实例,那么这个服务的配置文件一般是随着实例存在多份的,当多实例达到一定量级时,再加上可能开发环境、ST环境、UAT环境和生成环境等的配置文件,要增加或修改一项配置无疑是痛苦的。当然,我们可以通过一些自动化脚本或工具来完成这项配置,但哪怕是再智能的工具也必须要维护这些实例和不同环境的信息,尤其是在微服务项目中,开发和运维人员可能经常需要面对成百上千的服务,而一些IT大厂可能轻轻松松就能达到上万甚至几十万的服务实例数量,这就不是一些脚本和工具能轻松完成的工作了。因此,解决海量服务的配置问题成了微服架构的又一核心问题。
统一配置中心最大的好处就是不需要批量维护所有服务实例的配置信息,各个服务按需从配置中心读取配置,不需要修改所有的服务,只需修改配置中心的配置,不仅简单方便,而且效率高。还有一个好处就是相同的配置不需要维护多处,比如我们现在要做一个与第三方系统集成的项目,在项目中划分了很多独立的服务,可能服务A和服务B都需要与第三方系统进行交互,第三方系统提供了一些HTTP的接口给项目使用,那么关于第三方系统的接口配置可能既需要写在服务A中,也需要写在服务B中,哪怕它们是一模一样的,但如果有一个统一的配置中心,我们就只需要一份配置,然后服务A和服务B就都可以从这一份配置中读取配置信息。配置中心的设计也不是没有缺点。
中心化本身就有一些共性的弊端,其中最大的问题就是一旦配置中心不可用,带来的灾难就可能是成片的。设想一下,有上百个服务都依赖一套中心化的配置中心,如果这个配置中心“挂掉”,就意味着上百个服务都可能出现不可用的情况,这在微服务中是无法容忍的。当然,我们可以通过分布式集群等方式来保证中心服务的高可用。因此,现在摆在我们面前的问题就是如何实现一个高可用的配置中心服务。
笔者在几年前利用业余时间开发了一套统一配置中心,那时还是用关系型数据库做的配置信息的存储,在经过测试之后就投入公司的小型项目中试用,系统提供后台管理页面,可以支持不同项目、不同环境的信息配置,然后提供HTTP接口给外部系统调用来读取配置,最初使用效果不错,但随着项目时间的推进,很多问题就逐步暴露出来。
首先,经常会有人误操作,造成项目配置信息错乱,导致应用程序出错,甚至开始直接修改数据库来维护配置,这样做可能很方便,但导致维护更加混乱,而且操作追溯困难。其次,由于使用的是关系型数据库,而本身在设计上也是采用key和value的形式进行配置的编写,因此只能支持简单类型的数据配置,复杂的就只能通过JSON或一些自定义分隔符等方式来完成。再次,可能相同的服务在同时期会存在不同版本的配置文件,与不同环境不太一样,应用程序环境不同可能只是配置项的值不同,配置项一般都一样,但不同版本则需要在相同的应用下,各个环境中维护不同版本的配置,而这些配置可能都不一样。这一点如果不做特殊的设计,单从数据库层面似乎很难解决。
最后,就是Spring的支持不友好,由于使用的是HTTP方式,因此如果要集成Spring的一些加载配置的方式,就需要在客户端写大量的代码来完成这一需求,而且随着Spring Boot等框架的流行,支持Spring显得尤为重要。
当然,除了这些问题,还可能是使用的配置文件存在问题,每次修改配置都需要重新启动服务,因为配置只会在启动时加载,虽然也会有一些热加载的方式,但是没办法做到完全的动态获取配置,既然现在的策略是通过服务端来加载配置信息的,那么能不能做到如果修改了配置信息,就通知所有相关的服务端是一个问题。
综上所述,要实现一个操作可追溯,数据种类多样化,可维护版本,Spring支持友好、可动态更新、高可用的统一配置中心还是很难的。
当然,大公司往往比较热衷于让自己的团队来开发这些框架或服务,可能由于是太久之前的开源产品,功能并不是很完善,很多开源作者贡献了优秀的框架,这里就不一一列举了。本书中想给大家介绍的框架依然是Spring Cloud系列框架的Spring Cloud Config。
Spring Cloud Config是目前开源社区中最火的一款配置中心框架,它采用git作为配置信息的存储引擎,完美地解决了操作可追溯、配置数据种类多样、可维护版本等问题。
对Spring的支持自然不用说,完美地支持Spring Boot,而且可以继承Spring Cloud系列的其他组件,如集成Spring Cloud Netflix Eureka,可以将Spring Cloud Config部署多个实例,然后当作Eureka的Client注册到Server中,其他服务可以通过Eureka Server来发现Spring Cloud Config的服务,满足高可用的目的。也可以集成Spring Cloud Bus,通过对消息的发布和订阅,及时地通知服务配置信息的变更,从而达到动态更新配置信息的目的。
Spring Cloud Config的功能似乎很强大,而且也解决了之前所说的所有问题,那么到底如何使用呢?如何去集成这些高级的功能呢?下面为大家介绍Spring Cloud Config的具体用法。
Spring Cloud Config框架
Spring Cloud Config的设计结构有些类似Spring Cloud Netflix Eureka,也提供了Server和Client两个组件。借用Spring官方对它的描述,Spring Cloud Config为分布式系统中的外部化配置提供服务器和客户端支持。使用Config Server,可以在所有环境中管理应用程序的外部属 性 。 Config Client 将 服 务 器 上 的 配 置 映 射 到 SpringEnvironment和PropertySource中,因此它们非常适合Spring应用程序,并且可以与任何语言运行的应用程序一起使用。
当应用程序通过部署管道从开发到测试并进入生产时,SpringCloud Config可以管理这些环境之间的配置,并确保应用程序具有迁移时需要运行的所有内容。服务器存储后端的默认实现使用git,因此它可以轻松支持配置环境的标记版本,以及可用于管理内容的各种工具,当然也可以很容易地替换git的实现,具体运行原理如图3.1所示。
下面来看看具体是如何使用Spring Cloud Config的Server和Client的。
1. Spring Cloud Config Server
首先,可以去SpringInitializr的网站( https://start.spring.io/) 初始化我们的代码库,在Dependencies中添加Config Server,下面还是以Gradle为例,生成的配置如下。
其实需要引入
spring-cloud-config-server这个依赖,然后在对应的Spring Boot的启动类上增加@EnableConfigServer注解,代码如下。
之前提到过,Spring Cloud Config其实默认是使用的git作为配置文件的存储的,那么这里还需要配置Git仓库的地址、用户名密码等相关信息,所以在application.yml中添加如下配置。
当然,可以把配置中心作为一个Eureka Client注册到我们的注册中心,添加配置代码如下。
最后,可能配置信息会有些敏感,不希望公开访问,最简单的方式是集成Spring Security,Spring Cloud提供对应的Security的starter版本,这里可以引入
spring-cloud-starter-security的依赖库,在build.gradle中添加如下依赖配置。
然后,在application.yml文件中添加安全的配置,代码如下。
这时,有关Spring Cloud Config Server的配置就基本完成了。在服务正常启动后,即可通过Spring Cloud Config Client从git中读取配置信息了,如果此时Git仓库已经有了一些配置,那么可以通过HTTP的请求来认证是否配置成功,请求的规则如下。
假设我们现在要对项目的测试环境编写配置文件,在指定的GitHub 地 址 中 的 chapter 3/config-resources 目 录 下 添加application-name-test.yml 文 件 ( 在客户端不指定spring.profile.active时会默认读取application-name.yml的配置,和本地配置文件规则一致),内容如下。
然后在浏览器访问URL:
http://localhost:64949/applicationname/default(64949是因为配置了port是0而产生的随机端口号地址),如果配置了Spring Security,那么在浏览器中还需要输入用户名与密码,最后得到如下结果就证明Config Server配置成功了。
那么,在客户端如何与配置中心集成呢?Spring Cloud Config也提供了友好的客户端支持,不需要我们写任何代码,即可像读取本地配置一样读取配置中心的配置,下面来了解一下Spring Cloud Config Client的用法。
2. Spring Cloud Config Client
首先,我们在想要集成配置中心的项目中引入Spring CloudConfig Client的依赖包“
spring-cloud-starter-config”,然后需要在本地配置注册中心的信息。build.gradle需要引入依赖包如下。
因为需要先加载配置中心的信息,然后才能读取项目所需的配置信息,所以一般把Spring Cloud Config的配置写在bootstrap.yml文件中,bootstrap.yml文件的配置会先于application.yml加载。
当然,如果配置中心集成了Eureka,那么注册中心的配置也需要挪到bootstrap.yml文件中,具体的配置如下。
由上面的配置信息可以看到,因为是集成的注册中心,所以不需要关心配置中心具体的服务地址和端口,只需写上相应配置中心的应用名即可。由于在服务端加了安全组件,这里还需要配置正确的用户名和密码,然后就可以像读取本地配置一样获取配置中心的配置了,具体配置如下。
集成消息总线
在上述配置完成后,我们在微服务架构中所需的关于配置信息管理的大部分功能似乎已被满足,但项目中的场景往往没有这么简单,在有的项目中,配置信息还需要动态获取。若项目要求每次修改配置不重启服务器,则使用Spring Cloud Config应该怎么做?
一般的做法是把这些配置信息加到数据库中,通过数据库来存储和读取这些信息,只要数据库的数据发生变化,不需要重启服务器就能直接查询到最新的配置。但Spring Cloud Config使用git作为存储,这种方式可以满足动态获取配置的需求吗?答案是可以的,而且Spring Cloud Config做到的不只是可以动态获取,就连更新内存中的配置都不需要多写一行代码,在检测到配置发生变化时,Spring Cloud Config就能自动完成配置信息的更新,这是如何做到的呢?
Spring Cloud Config是通过集成了Spring Cloud Bus(消息总线)框架完成的这个功能,也就是说,当Spring Cloud Config的服务端检测到配置发生变化时,通过消息机制通知其他的客户端。这里不介绍Spring Cloud Bus的全部功能,只了解一下Spring Cloud Bus和Spring Cloud Config是如何配合工作的。
首先,我们知道Spring Cloud Bus并不是消息中间件,本身并不具备消息中间件的能力,只不过是集成了第三方的消息中间件,Spring Cloud Bus 提 供 了 两 个 消 息 中 间 件 的 starter 、AMQP(RabbitMQ)和Kafka。这里选择RabbitMQ作为我们的消息中间件,假设已经成功启动RabbitMQ,具体方法可以参考RabbitMQ的官网,有Docker环境的可以通过以下指令快速启动RabbitMQ。
其次,我们在之前Spring Cloud Config的Client端中引入新的包:spring-cloud-starter bus-amqp。build.gradle中的配置如下。
再次,在application.yml中添加关于RabbitMQ的配置,具体如下。
最后,需要引入actuator 框架 ,提供配置刷新的入口 ,build.gradle中依赖如下。
并且在application.yml中开启actuator的端点(Endpoint),内容如下。
可以访问
http://localhost:port/actuator查询所有的端点,在集成消息总线后,refresh的端点地址为/actuator/bus-refresh,我们可以通过POST请求该地址主动刷新配置,通过@RefreshScope注解可以指定配置刷新的范围,具体代码如下。
通过控制台输出可以看出请求refresh端点会清空服务本身的配置缓存,从而使服务重新从Config Server获取最新的配置,达到刷新配置的目的。而消息总线的作用就是在一个服务有多个实例时,我们不需要去refresh每个服务实例,只需刷新其中一个实例,消息总线会自动刷新其他的实例,达到多实例同步更新的效果。
那么,如何让配置自动刷新呢?这就需要相应的代码仓库有支持Webhook的功能,如我们示例中使用的GitHub就可以配置仓库的Webhook,也可以配置相应的事件通知。例如,当有新的commit时,就发送请求给配置的地址,如/actuator/bus-refresh,从而达到自动刷新配置信息的目的。
在实现了统一配置中心的设计之后,微服务架构看起来更加完善。回想一下,现在我们的微服务拥有自动注册和发现服务的功能,并且可以通过在客户端定义负载均衡策略,灵活地选择合适的服务端实例,然后有了统一配置中心,解决海量服务配置难的问题,那么这样的架构还有其他问题吗?答案是肯定的。
下文将通过微服务架构中又一个重要的架构设计“断路器”来寻找答案。
资料免费获取方式:一键三连(点赞+转发+关注小编),扫下方二维码免费获取~
以上是关于一文带你吃透Spring Cloud相关微服务组件及Spring Cloud Config框架的主要内容,如果未能解决你的问题,请参考以下文章
秒懂·云原生微服务篇 —— 三千字吃透Spring Cloud的组成