SpringCloud系列--Bus(1)消息总线介绍
1、概述
在下一篇SpringCloud系列–Config(2)动态刷新中,我们开发了SpringCloud Config手动版的定时更新机制,并且也发现了以下几个问题。
- 现有多个微服务客户端(例如:编号为 3355/3366/3377 的系统)。
- 每个微服务均需执行一条 post 请求,并采取人工刷新操作。
- 是否可以采用广播机制?即通过单一通知指令实现全系统响应。
- 是否可以在广泛范围内的应用中实现智能化处理流程设计?
现在我们来掌握 SpringBus 技术,并理解它是基于 SpringConfig 架构的一个重要升级。它不仅支持广播机制的同时提供自动刷新功能,并且最佳搭配则是将两者结合使用。
- 支持分布式架构下的自动刷新配置流程;
- 通过Spring Cloud Bus与Spring Cloud Config集成技术实现动态更新。

1.1 什么是Bus
Spring cloud bus通过轻量级的消息代理机制连接分布式系统中的各个节点,在这种架构下能够实现对状态变化(如配置修改)的通知以及其他管理操作的支持。其核心理念在于将总线视为类似可扩展的应用程序运行环境的一种分布式执行架构,并同时承担着应用程序之间的通信通道功能。目前该组件支持基于AMQP的消息代理以及Kafka协议的消息传输服务,并且在多个通道的相关文档中进一步探讨了具有特定配置特性的设置(这些配置可能根据通道设置而有所不同)。
概述:SpringCloud Bus是一个协调分布式系统节点与其轻量级消息传输系统之间连接的框架;该框架旨在整合基于Java的事件驱动处理机制以及相关的消息中转组件的功能
SpringCloud Bus目前涵盖当前主流协议如RabbitMQ及Kafka的支持,并本文采用RabbitMQ作为讲解重点
1.2 Bus能干嘛
SpringCloud Bus 负责管理和传递跨越分布式系统的消息,并类似于一个分布式的任务处理平台。它主要用于广播系统状态的变化以及传递事件,并同样也可作为微服务之间通讯的中转站。

1.3 为何被称为总线
1.3.1 什么是总线
在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例,都可以方便的广播一些需要让其他连接在该主题上的实例都知道的消息。
1.3.2 基本原理
ConfigClient 实例都监听MQ中同一个topic(默认是springcloubus),当一个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其他监听统一topic的服务就能得到通知,然后去更新自身的配置。
2、RabbitMQ环境配置
RabbitMQ的安装配置可参考官网:Downloading and Installing RabbitMQ
3、SpringCloud Bus动态刷新(全局广播)
注意:必须先具备良好的RabbitMQ环境。
SpringCloud Bus配合Config使用,集成Config可参考:SpringCloud系列–Config(1)分布式配置中心介绍和使用,演示广播效果,增加复杂度,参照其中的3355服务,建立一样的3366服务。
3.1 设计思想
全局广播通知方式有两种:
- 利用消息总线触发一个客户端/bus/refresh,进而刷新所有客户端的配置;

- 利用消息总线触发一个服务端ConfigServer的/bus/refresh端点,进而刷新所有客户端的配置(更加推荐)

注:此处的Config Server从Git拉取对应配置。
方式二架构显然更加合适,方式一不适合的原因如下:
- 打破了微服务的职责单一性,因为微服务本身是业务模块,它本不应该承担配置刷新职责;
- 破坏了微服务各节点的对等性;
- 有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就会增加更多的修改。
所以本文中将以第二种方式介绍全局广播通知。
3.2 配置中心服务端添加消息总线支持
3.2.1 pom.xml
配置中心服务端3344中添加RabbitMQ依赖:
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
3.2.2 application.yml
server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://github.com/kenashiwenziya/sprincloud-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'
增加了:
#rabbitmq相关配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
##rabbitmq相关配置,暴露bus刷新配置的端点
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: 'bus-refresh'
3.3 客户端添加消息总线支持
客户端3355和3366修改配置一致。
3.3.1 pom.xml
客户端3355中添加RabbitMQ依赖:
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
3.3.2 bootstrap.yml
server:
port: 3355
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:3344 #配置中心地址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: "*"
新增:
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
3.4 测试
启动3344、3355和3366后,修改Github上配置文件增加版本号为6,然后发送Post请求:
curl -X POST "http://localhost:3344/actuator/bus-refresh"
一次发送,处处生效。
测试配置中心:
http://config-3344.com/config-dev.yml
测试客户端:
http://localhost:3355/configInfo
http://localhost:3366/configInfo

获取配置信息,发现都已经刷新了,一次修改,广播通知,处处生效。
4、SpringCloud Bus动态刷新(定点通知)
如果不想全部通知,只想定点通知:只通知3355,不通知3366呢?
简单一句话就是:指定具体某一个实例生效而不是全部。
该链接指向配置中心指定的端口号处的actuator模块bus-refill功能。该链接指向配置中心指定的端口号处的actuator模块bus-refill功能. bus-refill请求不再直接发送至特定的服务实例. bus-refill请求不再直接发送至特定的服务实例. 而是由config server接收, 并通过destination参数来标识哪些服务或实例需要更新其配置信息.
本文涉及的地址为:http://localhost:3344/actuator/bus-refresh/\{destination\}。
在此案例中,则是以刷新操作位于端口号为\{port\}的\texttt{config-client}为例展开说明。
其中,在这种场景下,则是仅向指定端口\{port\}发送响应。
为了实现这一目标,则需通过curl工具发起POST请求至该URL即可实现目标。
5、通知总结

Happy Learning ~
