一、前言
在上一篇文章中,我们实现了基于Spring Cloud Config
分布式配置中心实现配置文件分离开来,统一放入Git
、SVN
等版本控制软件中管理,但在上一篇文章中,有个问题: 当Git/SVN
版本控制库中的微服务配置文件信息发生更改时,Config-Server
端可以实时的收到最新的通知发生响应的刷新,但是Config-Client
端无法动态感知这种变化,而最后我们提到的是通过使用手动方式发送/refresh
接口请求Config-Client
端,从而实现Git
仓库中的内容修改时,触发Config-Client
端应用程序的属性做出对应的更新。但是,若所有Git/SVN上触发的操作均需要手动去调用/refresh
接口刷新Config-Client
端应用程序的属性做出对应的更新,会变的越来越难以维护,而消息代理中间件(RabbitMQ或Kafka)是解决该问题最为合适的方案,也就是本篇将要实现的基于消息总线Spring Cloud Bus
实现动态刷新。
本文还是基于上一篇文章来实现。Spring Cloud系列教程(十):分布式配置中心Spring Cloud Config(Finchley版本) ,不清楚的同学请先阅读上一篇文章,本篇会在上一篇文章源码的基础上稍作修改,然后需要加入RabbitMQ依赖信息,同时我们需要安装RabbitMQ,关于RabbitMQ安装和开启比较简单,百度下文章也很多,需要引入的RabbitMQ依赖如下:
<!-- rabbitMQ-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
注意: 另外,如果你是通过刷新config-client端来广播配置文件的变化,那么config-client端还需要引入actuator监控依赖,由于引入的config-server端spring-cloud-config-server
依赖中已经默认集成了,所以config-server端无需引入。
<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
二、什么是Spring Cloud Bus消息总线
Spring Cloud Bus 是 Spring Cloud 体系内的消息总线,是Spring Cloud微服务全家桶中的一个组件,用来连接分布式系统的所有服务节点。将分布式的服务节点用轻量的消息代理(RibbitMQ、Kafka)连接起来。可以通过消息代理广播配置文件的更改实现全部节点的更新,或服务之间的通讯,也可以用于监控。解决了微服务数据变更,及时同步的问题。
三、Spring Cloud Bus如何工作
使用Spring Cloud Bus来实现配置文件的动态更新原理很简单,如下图:
-
刷新服务端流程
在上述整张流程图中: -
没有引入Bus消息总线之前的流程:
在Config-Server在启动的时候,首先会去远程Git仓库上读取配置文件信息,默认会持久化一份配置文件到硬盘上,同时还会在JVM内存中缓存一份,然后再返回给微服务Service-A/微服务Service-B/微服务Service-C;当微服务Service-A和微服务Service-B、微服务Service-C,也就是Config-Client端在启动的时候,会从Config-Server中加载读取各自服务对应的配置文件信息,在这个流程中,Config-Server充当了一个中间缓存的作用。 -
引入Bus消息总线之后的工作流程:
当远程Git仓库配置文件更新后,我向Config-Server中发送一个/bus/refresh请求,Config-Server收到这个请求之后,会将这个请求通过RabbitMQ广播出去,这样所有的微服务就都收到这个请求了,微服务收到这个请求之后就会自动去更新自己的配置文件。在这个系统中,从RabbitMQ的角度来看,所有的微服务都是一样的,所以这个/bus/refresh请求我们也可以在Config-Client节点上发出,一样能够实现配置文件动态更新的效果,但是这样做就破坏了我们微服务的结构,使得微服务节点之间有了区别,其实微服务本身是业务模块,它本不应该承担配置刷新的职责。所以刷新配置的请求我们还是放在Config-Server上来做比较合适。
四、准备工作
1. 工程准备
本篇博客基于上一篇博客源码做修改,下载地址: https://github.com/Thinkingcao/SpringCloudLearning/tree/master/springcloud-config
- springcloud-eureka-server : eureka注册中心,端口8888
- springcloud-config-server: 分布式配置中心服务端,端口8080
- springcloud-config-client: 分布式配置中心客户端,端口8081
在eureka-server、cpnfig-server、config-client 三个工程中都加入RabbitMQ依赖信息:
<!-- rabbitMQ-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2. congig-server配置文件
配置文件需要配置 消息队列 和 bus-refresh 自动刷新端点。/actuator/bus-refresh 端点会清除 @RefreshScope 缓存重新绑定属性。
#端口号
server:
port: 8080
#定义服务名称(服务注册到eureka名称)
spring:
application:
name: app-config-server
#Spring Cloud Config Server端配置
cloud:
config:
server:
git:
#远程存储库的URI地址。
uri: https://gitee.com/Thinkingcao/springcloud-config-repo
#使用远程Git仓库验证用户名。
username: xxxxxxxxx
#使用远程Git仓库密码。
password: xxxxxxxxx
#指定远程Git仓库的分支
default-label: master
#指定本地仓库地址用来存储获取远程Git上的配置文件
basedir: G:\temp\path\config-properties
##git仓库地址下的相对地址,可以配置多个,用,分割,也就是配置文件所在根目录文件夹名称
search-paths: config-respo
#标记以指示启用配置服务器发现(配置服务器URL将通过发现查找)。
discovery:
enabled: true
#bus配置,标记以打开跟踪
bus:
trace:
enabled: true
#rabbitmq配置
rabbitmq:
host: 127.0.0.1
port: 5672
username: admin
password: 111111
virtual-host: /
#在此指定服务注册中心地址,将当前服务注册到eureka注册中心上
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8888/eureka
#启动注册操作,该值默认为true。若设置为fasle将不会启动注册操作。是否需要去检索寻找服务,默认是true
register-with-eureka: true
#是否需要从eureka上获取注册信息
fetch-registry: true
#暴露bus刷新配置的端点
management:
#关闭安全校验
security:
enable: false
#暴露端点
endpoints:
web:
exposure:
include: bus-refresh # 需要开启的端点
#exclude: # 不需要开启的端点
base-path: /actuator # 访问端点根路径,默认为 /actuator
3. config-client配置文件
#服务端口号
server:
port: 8081
#定义服务名称(服务注册到eureka名称)
spring:
application:
name: order
#cloud config配置
cloud:
config:
name: ${spring.application.name}
profile: dev #profile对应config server所获取的配置文件中的{profile}
label: master #指定Git仓库的分支,对应config server所获取的配置文件的{label}
discovery:
#标记以指示启用配置服务器发现(配置服务器URL将通过发现查找)
enabled: true
#读取config-server注册地址
service-id: app-config-server
#uri: http://127.0.0.1:8080/
#bus配置,标记以打开跟踪
bus:
trace:
enabled: true
#rabbitmq配置
rabbitmq:
host: 127.0.0.1
port: 5672
username: admin
password: 111111
virtual-host: /
#在此指定服务注册中心地址,将当前服务注册到eureka注册中心上
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8888/eureka
#启动注册操作,该值默认为true。若设置为fasle将不会启动注册操作。是否需要去检索寻找服务,默认是true
register-with-eureka: true
#是否需要从eureka上获取注册信息
fetch-registry: true
4. eureka-server配置文件
#服务端口号
server:
port: 8888
#定义服务名称(服务注册到eureka名称)
spring:
application:
name: app-thinkingcao-eureka
#bus配置,标记以打开跟踪
bus:
trace:
enabled: true
#rabbitmq配置
rabbitmq:
host: 127.0.0.1
port: 5672
username: admin
password: 111111
virtual-host: /
eureka:
instance:
#Eureka注册中心ip地址
hostname: 127.0.0.1
client:
serviceUrl:
#注册地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#表示是否需要将自己注册给自己的注册中心,因为自己是注册中心,单机版本时不需要,设置为false(集群的时候需要是为true)
register-with-eureka: false
#因为自己是注册中心,不需要去检索服务信息,单机版本时不需要,设置为false(集群的时候需要是为true)
fetch-registry: false
#Eureka自我保护机制
server:
#关闭eureka自我保护机制false(默认为true)
enable-self-preservation: false
# 清理间隔(单位毫秒,默认是60*1000)
eviction-interval-timer-in-ms: 2000
5. RabbitMQ添加用户
输入用户名密码就可以创建了,tags表示用户标签,相当于角色,可选值有management、none、policymaker、monitoring和administrator,不同取值所对应的权限区别如下:
-
none
1.不能访问 management plugin -
management
用户可以通过AMQP做的任何事外加:
1.列出自己可以通过AMQP登入的virtual hosts
2.查看自己的virtual hosts中的queues, exchanges 和 bindings
3.查看和关闭自己的channels 和 connections
4.查看有关自己的virtual hosts的“全局”的统计信息,包含其他用户在这些virtual hosts中的活动 -
policymaker
management可以做的任何事外加:
1.查看、创建和删除自己的virtual hosts所属的policies和parameters -
monitoring
management可以做的任何事外加:
1.列出所有virtual hosts,包括他们不能登录的virtual hosts
2.查看其他用户的connections和channels
3.查看节点级别的数据如clustering和memory使用情况
4.查看真正的关于所有virtual hosts的全局的统计信息 -
administrator
policymaker和monitoring可以做的任何事外加:
1.创建和删除virtual hosts
2.查看、创建和删除users
3.查看创建和删除permissions
4.关闭其他用户的connections
五、基于Webhook实现全自动化配置刷新
消息总线(Bus)的典型应用场景就是配置中心客户端刷新。Spring Cloud官方推荐的是基于 Actuator 的配置刷新,这种方式还是需要人工干预,手动调用actuator/refresh接口,只不过我们只需要刷新一个Config-Server端点, Spring Cloud Bus 的代理(RabbitMQ或者KafKa)广播功能,让 Config Client 都订阅配置更新事件,当配置更新时,触发其中一个端的更新事件,Spring Cloud Bus 就把此事件广播到其他订阅客户端,以此来达到批量更新,当使用Spring Cloud Bus 时,Config-Client的数量我们就无需关心了。
1. Webhook配置
WebHooks相当于是一个钩子函数,我们可以配置当向Git(GitLab/GitHub/Gitee)仓库push代码时触发这个钩子函数,自动调用"http://localhost:8080/actuator/bus-refresh/{destination}"
请求,帮助我们自动发送一个POST请求刷新Config-Client和Config-Server,这里以Gitee为例来介绍下其使用方式,这里当我们向配置仓库push代码时就会自动刷新服务配置了。
- 添加Webhook配置如下
- 使用Webhook 整体流程
- Webhook 监听被触发,给 ConfigClient A 发送 bus-refresh 请求刷新配置
- ConfigClient A 读取 ConfigServer 中的配置,并且发送消息给 Bus
- Bus 接收消息后广播通知其他 ConfigClient
- 其他 ConfigClient 收到消息重新读取最新配置
关于Webhook的使用,这里只做介绍,因为个人觉得当配置文件发生Push更改的时候,手动调用一下"bus-refresh/"
接口即可,没什么工作量,没有必要使用Webhook。
六、查看RabbitMQ
首先开启RabbitMQ和RabbitMQ的UI界面插件,然后启动eureka-server、cpnfig-server、config-client这3个服务,访问RabbitMQ服务的UI界面: http://localhost:15672, 账号密码默认:guest/guest,显示如下:
新增了3个队列:
新增一个springCloudBus交换机
点开springCloudBus发现交换机绑定了3个队列:
七、测试
1. 查看端点是否开启
访问:http://localhost:9091/actuator 可以看到已经开启了 bus-refresh
自动刷新端点
Git仓库配置文件值如下:
访问: http://localhost:8081/message , 响应结果如下:
https://thinkingcao.blog.csdn.net/
2. 更改Git配置文件值
blog:
url: www.baidu.com
3. 刷新Config-Server端接口
PostMan访问: http://localhost:8080/actuator/bus-refresh 即可。
然后再次访问: http://localhost:8081/message,显示刷新后的结果,如下: