Spring Cloud Bus
文章目录
Spring Cloud Bus是什么
Spring Cloud Bus叫事件总线,当我们的系统中服务越来越多之后,维护这样的刷新清单将会变得非常繁琐麻烦,而且容易犯错。Spring Cloud Bus使用 message broker 来连接分布式系统的所有节点。它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控。本文要讲述的是用Spring Cloud Bus实现通知微服务架构的配置文件的更改。
SpringCloud Bus会向外提供一个http接口,即下图中的/bus/refresh。我们将这个接口配置到git的webhook上,当git上的内容发生改变时,就会自动调用/bus/refresh接口。Bus就会通知ConfigServer,configserver会发布更新消息到消息总线的消息队列,其他服务订阅到该消息就会信息刷新,从而实现整个微服务进行自动刷新。
Spring Cloud Bus的两种实现方式图解
- f方法1 : 某个微服务承担刷新配置的任务
①提交配置出发post请求调用客户端A-3的/bus/refresh接口(spring boot 2.0.x以后是/actuator/bus-refresh)
②客户端A-3收到请求从Server端更新配置并且发送给Spring Cloud Bus消息总线
③Spring Cloud Bus接收消息并通知给其他连线在总线上的客户端,所有总线上的客户端均能接收到消息。
④其他客户端接收到消息,请求Server端获取最新配置
⑤全部客户端均获取到最新的配置
以上方式存在两个问题
- 微服务本身是业务模块,而不应该承担配置刷新的职责,打破了微服务的单一原则.
- WebHook的配置也随着承担刷新配置的微服务节点发生变化.
- 方法2: 配置中心Server端承担起配置刷新的职责
①提交配置触发post请求给server端的/bus/refresh接口(spring boot 2.0.x以后是/actuator/bus-refresh)
②server端接收到请求并发送给SpringCloud Bus总线
③Sping Cloud Bus接收到消息并通知给其他连接的总线的客户端
④其他客户端接收到通知,请求Server端获取最新配置
⑤全部客户端获取到最新的配置
我们看到WebHook的直接请求server端,WebHook的配置不会发生变化,Server端承担起配置刷新的职责,不要业务端处理刷新了.完美解决上述的问题.
快速开始一个Spring Cloud Bus
Spring Cloud Bus通过添加Spring Boot自动配置,您需要做的是启用总线是将spring-cloud-starter-bus-amqp
或spring-cloud-starter-bus-kafka
添加到您的依赖关系管理中,配置上RabbitMQ或Kafka环境,如果是配置RabbitMQ,application.yml中需添加RabbitMQ的配置信息,如下:
spring:
rabbitmq:
host: mybroker.com
port: 5672
username: user
password: secret
/actuator/*
执行器命名空间下还有一些http端点. /actuator/bus-refresh/{destination}和/actuator/bus-refresh.其中destination目的地是ApplicationContext
ID,默认情况下,Spring Boot将ContextIdApplicationContextInitializer
中的ID设置为spring.application.name
,活动配置文件和server.port
的组合。比如/actuator/bus-refresh?destination=customers:**" 即刷新服务名为customers的所有服务。/actuator/bus-refresh
将重新加载每个应用程序的配置.一定要是Post请求,并且配置文件中加上注解如下:
management.endpoints.web.exposure.include=bus-refresh
Spring Cloud Bus的实例演示
- 修改所有节点的配置
- 新建5个Demo放在github上 https://github.com/fangjian0423/rocketmq-binder-demo/tree/master/rocketmq-bus-demo 。
- 访问任意节点提供的 Controller 提供的获取配置的地址(key为
hangzhou
):
curl -X GET 'http://localhost:10001/bus/env?key=hangzhou'
所有节点返回的结果都是 unknown,因为所有节点的配置中没有 hangzhou
这个 key。
-
Bus 内部提供了 EnvironmentBusEndpoint 这个 Endpoint 通过 message broker 用来新增/更新配置。
访问任意节点该 Endpoint 对应的 url /actuator/bus-env?name=hangzhou&value=alibaba 进行配置项的新增(比如访问 node1 的url):
curl -X POST 'http://localhost:10001/actuator/bus-env?name=hangzhou&value=alibaba' -H 'content-type: application/json'
- 再次访问所有节点
/bus/env
获取配置:
$ curl -X GET 'http://localhost:10005/bus/env?key=hangzhou'
alibaba%
~ ⌚
$ curl -X GET 'http://localhost:10004/bus/env?key=hangzhou'
alibaba%
~ ⌚
$ curl -X GET 'http://localhost:10003/bus/env?key=hangzhou'
alibaba%
~ ⌚
$ curl -X GET 'http://localhost:10002/bus/env?key=hangzhou'
alibaba%
~ ⌚
$ curl -X GET 'http://localhost:10001/bus/env?key=hangzhou'
alibaba%
所有节点都新增了一个 key 为 hangzhou
的配置,且对应的 value 是 alibaba
。
- 修改部分节点的配置
- 比如在 node1 上指定 destination 为 rocketmq-bus-node2 (node2 配置了 spring.cloud.bus.id 为
rocketmq-bus-node2:10002
,可以匹配上) 进行配置的修改:
curl -X POST 'http://localhost:10001/actuator/bus-env/rocketmq-bus-node2?name=hangzhou&value=xihu' -H 'content-type: application/json'
- 获取配置如下:
$ curl -X GET 'http://localhost:10005/bus/env?key=hangzhou'
alibaba%
~ ⌚
$ curl -X GET 'http://localhost:10004/bus/env?key=hangzhou'
alibaba%
~ ⌚
$ curl -X GET 'http://localhost:10003/bus/env?key=hangzhou'
alibaba%
~ ⌚
$ curl -X GET 'http://localhost:10002/bus/env?key=hangzhou'
xihu%
~ ⌚
$ curl -X GET 'http://localhost:10001/bus/env?key=hangzhou'
xihu%
我们看到,只有 node1 和 node2 修改了配置,其余的 3 个节点配置未改变。node1的改变是因为在 node1 上发送消息,bus也会在node1进行配置修改.