在上一篇文章中,我们说到了如果config server的配置文件发生了修改,config client可以通过执行/actutor/refresh来实现热刷新。但是这也做的弊端也很明显,如果有几十上百个config client,需要一个服务一个服务地发送请求,可能会被运维兄弟打死。。。。。。那么在微服务项目中,Spring Cloud Bus这个必备组件就不得不出场了。
Spring Cloud Bus,俗称消息总线,通过使用轻量级的消息代理来构建一个公共地消息主题让系统中所有的微服务实例都连接上来,在总线上的各个实例都可以方便地广播一些需要让其他连接在该主题上地实例都知道消息,例如配置信息的变更或者其他一些管理操作等。
消息代理
消息代理是一种消息验证、传熟、路由的架构模式,他在应用程序之间起到通信调度并最小化应用之间的依赖的作用,是的应用程序可以高效的解耦通信过程。他的核心是一个消息的路由程序,用来实现接收和分发消息,并根据设定好的消息处理流来转发给正确的应用。
常用的使用场景:
- 将消息路由到一个或多个目的地
- 消息转化为其他的表现方式
- 执行消息的聚集、消息的分解,并将结果发送到他们的目的地,然后重新组合响应返回给消息用户
- 调用web服务来检索数据
- 响应事件或错误
- 使用发布-订阅模式来提供内容或基于主题的消息路由
目前支持Spring Cloud Bus的消息中间件只有这两个:RabbitMQ和Kafka。
RabbitMQ实现消息总线
关于RabbitMQ,欢迎查看我之间的博客:消息队列之RabbitMQ
消息总线bus是基于Actuator对外提供热刷新服务。
1.扩展之前的config-client项目
因为我这边用config-client做测试,引入spring-cloud-starter-bus-amqp会下图这个错,
所以在引入bus-amqp的依赖的时候,改了spring boot的版本,我其他spring cloud组件所用的spring boot版本都是2.3.10.RELEASE,在引入bus组件后spring cloud的版本修改为2.1.4.RELEASE,spring cloud的版本修改为Greenwich.SR1。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.charon</groupId>
<artifactId>config-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>config-client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 添加spring cloud bus的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.配置文件的信息
spring.application.name=config-client
server.port=9011
spring.cloud.compatibility-verifier.enabled=false
# 需要配置spring cloud config server位置和要加载的相关参数
# spring cloud config server的连接地址
spring.cloud.config.uri=http://localhost:8888
# 要加载的配置文件主体命名
spring.cloud.config.name=config
# 要加载的配置文件的profile,默认为default
spring.cloud.config.profile=default
# 要加载的配置文件所在的分支命名,默认为null,相当于master
spring.cloud.config.label=master
eureka.client.serviceUrl.defaultZone=http://eureka-server1:9001/eureka/
# 配置rabbitMQ的相关信息
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
# 设置应用是否连接到消息总线上
spring.cloud.bus.enabled=true
management.endpoints.web.exposure.include=info,health,refresh,bus-refresh
3.打包成jar,然后使用java -jar命令启动两个服务,9011,9012
如下图所示,访问9011和9012得到的配置信息如下:
访问rabbitmq的页面,可以看到默认创建了一个exchange:springCloudBus
4.修改git上的值,并使用postman发送post请求。
5.查看
如此这样,只需要发送一次bus-refresh请求,两个config client服务的配置都发生了修改。
详细说明
在本示例中,我使用的架构图如下所示:
其中包含了Git仓库,config server以及几个config client服务,config client服务都引入了Spring Cloud Bus,所以他们都连接到了RabbitMQ的消息总线上。
当我们将系统启动起来之后,图中“Service A”的三个实例会请求Config Server 以获取配置信息,Config Server根据应用配置的规则从Git仓库中获取配置信息并返回。
此时,若我们需要修改“Service A”的属性。首先,通过Git管理工具去仓库中修改对应的属性值,但是这个修改并不会触发“Service A”实例的属性更新。我们向“Service A”的实例3发送POST请求,访问/bus/refresh(本示例中为/actuator/bus-refresh)接口。此时,“Service A”的实例3就会将刷新请求发送到消息总线中,该消息事件会被“Service A”的实例1和实例2从总线中获取到,并重新从Config Server中获取它们的配置信息,从而实现配置信息的动态更新。
而从Git仓库中配置的修改到发起/bus/refresh的 POST请求这一步可以通过Git仓库的Web Hook来自动触发。由于所有连接到消息总线上的应用都会接收到更新请求,所以在 Web Hook中就不需要维护所有节点内容来进行更新,从而解决了上一章中仅通过Web Hook来逐个进行刷新的问题。
RabbitMQ使用的为topic交换器,配合#路由键做广播消息处理。
指定刷新范围
Spring Cloud Bus也支持在bus-refresh接口中提供一个destination的参数,用来定位具体要刷新的服务。
将git残酷中的age值从100改为101,在postman中指定刷新9011的服务
这样就是有9011服务的值修改了,而9012服务的值并没有修改。
出处:https://www.cnblogs.com/pluto-charon/p/15115462.html