文章目录
一、前言
1、使用背景
在学习完Config之后,我们发现了一个问题就是每当配置中心配置发生变化以后,都需要将每个微服务重新启动一遍,这样对于某些大型项目而言是很痛苦的,然后我们就又引入了动态刷新功能,每当配置中心配置变化后,我们的运维小哥就手动给每一个微服务都发送一个POST请求用于更新配置,这样便免于重新启动服务,节约时间,但是这样的动态刷新还是不够彻底,我们如何才能彻底解放运维小哥的双手呢?那就是使用Spring Cloud Bus配合Spring Cloud Config使用实现动态刷新配置。
2、什么是总线
在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例,都可以方便地广播─些需要让其他连接在该主题上的实例都知道的消息。
3、Spring Cloud Bus简介
Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能,它能管理和传播分布式系统间的消息,就像一个分布式执行器,可用于广播状态更改、事件推送等,也可以当作微服务间的通信通道,目前支持RabbitMQ和Kafka,本文便是使用RabbitMQ。
二、工作流程
1、消息发送给一个客户端而刷新所有的配置
- 配置更新,推送到Git仓库。
- Config Server配置中心同步配置。
- 使用订阅了消息的主机给其中一个服务发送一个Post bus/refresh更新请求。
- 该服务向服务配置中心拉取最新配置,并将信息发送给消息总线。
- 这个消息将会通过消息总线广播出去,域内指定或所有服务收到消息就回去服务配置中心拉取最新配置。
2、消息发送给服务配置中心来刷新所有配置
- 配置更新,推送到Git仓库
- Config Server配置中心同步配置
- 使用订阅了消息的主机给服务配置中心发送一个Post bus/refresh更新请求
- 服务配置中心给消息总线发送通知请求刷新配置
- 消息总线向域内指定或所有服务发送更新通知消息
- 服务从服务配置中心拉取最新配置
3、采用第二种的原因
相比之下,第二种应该更合理,图一不合理的原因如下:
- 打破了微服务的职责单一性,因为微服务本身是业务模块,它本不应该承担配置刷新的职责。如果这个服务挂了,那是不是就会既影响订单服务,又影响通知服务,数罪并罚死得更惨。
- 破坏了微服务各节点的对等性
- 有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就会增加更多的修改
三、基本原理
ConfigClient实例都监听MQ中同一个topic(默认是springCloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置。
四、RabbitMQ安装及环境配置
这里只提供官网下载地址,具体配置自行百度
1、ErLang
使用RabbitMQ时需要下载安装ErLang环境,因为RabbitMQ是用ErLang语言编写的。
官网下载地址:ErLang下载
2、RabbitMQ
官网下载地址:RabbitMQ下载
五、实现动态刷新
1、创建一个新的客户端
基于上一篇文章,再次创建一个与8888相同的8889,步骤省略,区别仅在于配置文件端口号声明为8889
2、ConfigServer8080添加消息总线的支持
这里采用第二种通知方式,直接通知配置中心,更加合理
(1)pom文件
<!-- 添加消息总线RabbitMQ支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
(2)yml文件
server:
port: 8080
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://gitee.com/F_promise/springcloud-config.git #GitHub上面的git仓库名字
####搜索目录
search-paths:
- springcloud-config
####读取分支
label: master
#rabbitmq相关配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
##rabbitmq相关配置,暴露bus刷新配置的端点
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: 'bus-refresh'
3、ConfigClient添加消息总线的支持
8888,8889配置相同
(1)pom文件
<!-- 添加消息总线RabbitMQ支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
(2)yml配置文件
server:
port: 8888
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:8080 #配置中心地址k
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
4、重启测试
- 先单独访问每个项目,查看是否能正常访问
- 修改git仓库的内容
- 查看服务端ConfigServer8080是否能正常自动更新数据
- 8080上的数据可以正常更新后,发送post请求:curl -X POST “http://localhost:3344/actuator/bus-refresh”
- 再次访问客户端8888和8889,可以发现内容也进行了实时更新。
六、动态刷新的定点通知
在配置更新后,我们有时候有这种需求,只希望某一部分服务更新配置,另一部分不更新,那么就需要进行定点通知,放在本文中,也就是只通知8888或者8889,另一个不通知。
这里给个公式:
http://localhost:配置中心的端口号/actuator/bus-refresh/{destination}
请求就会发给config server并通过destination参数类指定需要更新配置的服务或实例
例如:
#只通知8888,config-client为服务名
curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:8888"
#只通知8889
curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:8889"
#假如我们现在有三个客户端8888,8889,8890,但是想通知8888,8889,不通知8890
curl -X POST "http://localhost:3344/actuator/bus-refresh/{config-client:8888,config-client:8889}"
#或者
curl -X POST "http://localhost/bus/refresh?destination=config-client:8888&config-client:8889"