Spring Cloud 入门 ---- Bus 消息总线
介绍
Spring Cloud Bus 是用来将分布式系统的节点与轻量级消息系统链接起来的框架,
它整合了 Java 的事件处理机制和消息中间件的功能。
Spring Cloud Bus 目前支持 RabbitMQ 和 Kafka。Spring Cloud Bus 配合 Spring Cloud Config 使用可以实现配置的动态刷新。
Spring Cloud Bus 能管理和传播分布式系统间的消息,就像一个分布式执行器,可以用于广播状态更改、事件推送等,也可以当作微服务间的通信通道。
什么是总线
在微服务架构系统中,通常会使用
轻量级的消息代理
来构建一个共用的消息主题
,并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线
。在总线上的各个实例,都可以方便地广播一些需要让其它连接在该主题上的实例都知道的消息。
基本原理
Config Client 实例都监听 MQ 中同一个 topic(默认是 springCloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到 Topic 中,这样其它监听同一 Topic 的服务就能得到通知,然后去更新自身的配置。
Bus 之 RabbitMQ 环境准备
Linux版
Spring Cloud Bus 目前支持 RabbitMQ 和 Kafka,这里我们选择使用 RabbitMQ ,关于 RabbitMQ 的安装与配置请参考:https://blog.csdn.net/qq_39668819/article/details/107391505
如图我们使用 docker 安装 rabbitMQ 并且成功启动。启动成功后,进入浏览器打开后台管理界面【http://192.168.0.163:15672/】,如下图:默认用户名与密码都是 guest
windows 版
CSDN:上传的安装包地址:https://download.csdn.net/download/qq_39668819/13111699
一、安装Erlang,下载地址:http://erlang.org/download/otp_win64_22.2.exe
二、安装RabbitMQ,下载地址:https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.8.2/rabbitmq-server-3.8.2.exe
三、安装完成后,进入RabbitMQ安装目录下的sbin目录:
在 RabbitMQ 安装目录下的 sbin 目录的地址栏输入 cmd 并回车启动命令行,然后输入以下命令启动管理功能:
rabbitmq-plugins enable rabbitmq_management
这时你就可以搜索到 RabbitMQ 的启动和停止的运行程序
四、访问地址查看是否安装成功:http://localhost:15672/
动态刷新全局广播准备工作
创建 config 客户端集群
为了演示广播效果,我们还需要增加一个 config 客户端模块;与前面创建 config配置中心集群类似,我们可以复制 3355 创建一个 3356 客户端模块,具体步骤如下:
一、将 bootstrap.yml 配置文件改名为 bootstrap-one.yml,并复制它创建 bootstrap-two.yml,bootstrap-two.yml 配置基本与 bootstrap-one.yml 一致,主要修改端口号;具体修改如下:
server:
port: 3356
eureka:
client:
instance-id: config-client-3356
二、修改 ConfigClientController
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${server.port}")
private String port;
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return "serverPort: "+port + "\t\n\n configInfo: " +configInfo;
}
}
三、修改 ConfigClientApplication 启动服务,并复制一份为 ConfigClientApplication3356,具体修改如下:
四、启动这两个服务,登录 Eureka 注册中心,查看服务是否注册成功。
至此,config 客户端集群创建完成。
动态刷新全局广播设计思想
关于动态刷新全局广播的方法一共提供了两种设计思想,下面我们将分别介绍这两种思想。
一、利用消息总线触发一个客户端
/bus/refresh
,进而刷新所有的客户端配置。【不太推荐】
二、利用消息总线触发一个服务端 ConfigServer 的
/bus/refresh
端点,进而刷新所有的客户端配置。【更加推荐】
以上我们选择方式二,方式一有如下几种缺陷:
- 打破了微服务的职责单一性,因为微服务本身是业务模块,他本不应该承担配置刷新的职责
- 破环了微服务各节点的对等性
- 有一定的局限性。例如:微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动更新,那就会增加更多的修改
动态刷新全局广播配置实现
修改配置中心
导入 pom 依赖
<!--添加消息总线 RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
修改 yml,
application-one.yml
与application-two.yml
都需要修改,如下:
spring:
application:
name: config-center-service
security:
# 配置spring security登录用户名和密码
user:
name: akieay
password: configcenter
#rabbitmq相关配置 15672是web管理界面端口 5672是MQ访问端口
rabbitmq:
host: 192.168.0.163
port: 5672
username: guest
password: guest
virtual-host: /
cloud:
config:
server:
git:
force-pull: true
uri: https://github.com/admin-strat/springcloud-config.git #github上面的git仓库
username: xxxxxxx
password: xxxxxxx
# 搜索目录
search-paths:
- springcloud-config
# 读取分支
label: master
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "bus-refresh"
添加配置类
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
修改完成后,重启服务,在注册中心即可以查看服务是否注册成功。
修改 config 客户端
导入 pom 依赖
<!--添加消息总线 RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
修改 yml,同样
bootstrap-one.yml
与bootstrap-two.yml
都需要修改,具体修改如下:
spring:
application:
name: config-client-service
cloud:
config:
# uri: http://localhost:3344 #配置中心地址
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取
username: akieay
password: configcenter
discovery:
enabled: true
service-id: CONFIG-CENTER-SERVICE
#rabbitmq相关配置 15672是web管理界面端口 5672是MQ访问端口
rabbitmq:
host: 192.168.0.163
port: 5672
username: guest
password: guest
virtual-host: /
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
修改业务类
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${server.port}")
private String port;
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return "serverPort: "+port + "\t configInfo: " +configInfo;
}
}
重启服务,在注册中心查看服务注册情况。
动态刷新全局广播
启动所有服务后,我们登录 RabbitMQ 的控制台可以发现 Spring Cloud Bus 创建了一个叫
springCloudBus
的交换器及四个以Queue springCloudBus.anonymous
开头的队列:
接下我我们将详细的演示 动态刷新全局广播 ,并且可以在 RabbitMQ 控制台查看相关信息。
一、访问 github 查看
config-dev.yml
的配置信息
二、并访问:http://localhost:3344/master/config-dev.yml 、http://localhost:3345/master/config-dev.yml、 http://localhost:3355/configInfo、http://localhost:3356/configInfo 查看是否能正常获取到配置信息。
三、修改 github 上
config-dev.yml
的配置信息,修改版本号;
四、这时候访问:http://localhost:3344/master/config-dev.yml 、http://localhost:3345/master/config-dev.yml、 http://localhost:3355/configInfo、http://localhost:3356/configInfo 可以发现 3344 与 3345 配置中心已经更新配置信息,而 3355 与 3356 客户端没有更新配置信息。
五、这时我们使用 postman 调用 http://localhost:3344/actuator/bus-refresh,发送 post 请求给配置中心,实现
利用消息总线触发一个服务端 ConfigServer 的 /bus/refresh 端点,进而刷新所有的客户端配置
;注意:由于我们使用security
来实现了配置中心的认证,所以在刷新配置中心端点时也需要添加我们设置好的用户名与密码,用以通过security
的认证才能实现刷新功能。
六、查看: http://localhost:3355/configInfo、http://localhost:3356/configInfo 可以发现配置信息已经刷新。
以上即是 动态刷新全局广播 功能的演示,通过刷新配置中心实现了一次修改,广播通知,处处生效的功能。
动态刷新定点通知
在实际工作中,我们可能会遇到 修改配置中心配置后,不需要全部通知,只需要通知部分服务的需求;这时上面介绍的全局广播将不再适合,这时我们可以通过定点通知来实现刷新指定的服务节点。
简单来说就是指定具体的某一个实例生效而不是全部,具体公式为:
http://配置中心地址【ip+port】/actuator/bus-refresh/{destination} destination:为微服务的别名+端口
/bus/refresh 请求不在发送到具体的服务实例上,而是发送给 config server 并通过 destination 参数类指定需要更新配置的服务或实例
测试定点刷新
我们沿用之前的服务,通过上面全局广播的演示,当前 github 配置为:
我们需要演示的是,在修改 github 配置后,刷新 config 客户端 3355 而同时刷新 3356;具体步骤如下:首先我们需要修改 github 上的配置,如下:
再调用:
http://localhost:3344/actuator/bus-refresh/CONFIG-CLIENT-SERVICE:3355
查看:http://localhost:3355/configInfo 与 http://localhost:3356/configInfo 可以看到 3355 已经更新而 3356 还是原来的配置。
通知总结: