本文是Spring Cloud专栏的第十二篇文章
一、前言
由于在没有使用消息总线的时候,我们如果需要修改某个配置,如果涉及修改的微服务节点比较多,我们需要手动的一个节点一个节点的刷新非常麻烦,在微服务架构的系统中,我们通常会使用轻量级的消息代理来构建一个共用的消息主题让系统中所有微服务实例都连接上来,由于该主题中产生的消息会被所有实例监听和消费,所以我们称它为消息总线。在总线上的各个实例都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息,例如配置信息的变更或者其他一些管理操作等。
由于消息总线在微服务架构系统中被广泛使用,所以它同配置中心一样,几乎是微服务架构中的必备组件。 Spring Cloud作为微服务架构综合性的解决方案,对此自然也有自己的实现,通过使用 Spring Cloud Bus, 可以非常容易地搭建起消息总线,同时实现了一些消息总线中的常用功能,比如,配合 Spring Cloud Config实现微服务应用配置信息的动态更新等。
目前版本,Spring Cloud Bus仅支持两款中间件产品,RabbitMQ和Kafka,本案例使用RabbitMQ实现Spring Cloud Bus
二、整合消息总线Bus
2-1、修改以前的springcloud-config-server,springcloud-config-client块添加依赖,actuator依赖父模块已经引入,此处不需要再次引入
<!--spring cloud bus 整合rabbitmq -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2-2、http://47.112.11.147:15672/ 用户名admin密码123456
2-3、在springcloud-config-server模块application.yml中添加bus,和rabbitmq的相关配置以及暴露bus-refresh端点
spring:
cloud:
bus:
#控制bus消息总线是否能用
enabled: true
#打开bus追踪
trace:
enabled: true
rabbitmq:
addresses: 47.112.11.147
port: 5672
username: admin
password: 123456
virtual-host: /
management:
endpoints:
web:
exposure:
include: ["info","health","bus-refresh"]
在springcloud-config-client服务中application.yml只添加rabbitmq相关配置就行了
spring:
rabbitmq:
addresses: 47.112.11.147
port: 5672
username: admin
password: 123456
virtual-host: /
2-4、启动springcloud-config-server查看日志:
2-5、启动配置中心服务端查看bus相应的转换器Exchange以及Type对应的topic(发布订阅Receiving messages based on a pattern (topics))
如果不懂RabbitMQ的话也不影响你的Bus使用
查看rabbitmq控制台看到bus相应对列创键了
查看绑定关系,springcloudbus相应对列已经绑定到了springcloudbus转换器上了
2-6、启动config client客户端看到该对列也绑定到了spirngcloudbus转换器上
2-7、我们在复制一个config client其他不变boostrap.yml配置文件如下,创键启动类启动
server:
port: 8882
spring:
application:
name: springcloud-config-client
cloud:
config:
#uri则表示配置中心的地址
#uri: http://localhost:8888
#注:config 客户端在没有 spring.cloud.config.name属性的时候,服务端{application} 获取的是客户端
#spring.application.name的值,否则,获取的是 spring.cloud.config.name的值。
#1)、当没有spring.cloud.config.name时,客户端获取的是spring.application.name 所对应的git库中的文件,并且只能
#获取一个文件,
#2)、当一个项目中有需求要获取多个文件时,就需要用到spring.cloud.config.name这个属性,以逗号分割
name: configclient
profile: dev
#label对应了label部分
label: master
# username: coding-farmer
# password: 123456
discovery:
#表示开启通过服务名来访问config-server
enabled: true
#则表示config-server的服务名
service-id: springcloud-config-server
#失败快速响应
fail-fast: true
retry:
#配置重试次数,默认为6
max-attempts: 6
#初始重试间隔时间,默认1000ms
initial-interval: 1000
#间隔乘数,默认1.1
multiplier: 1.1
#最大间隔时间,默认2000ms
max-interval: 2000
rabbitmq:
addresses: 47.112.11.147
port: 5672
username: admin
password: 123456
virtual-host: /
eureka:
client:
service-url:
defaultZone: http://localhost:8700/eureka
#客户端每隔30秒从Eureka服务上更新一次服务信息
registry-fetch-interval-seconds: 30
#需要将我的服务注册到eureka上
register-with-eureka: true
#需要检索服务
fetch-registry: true
#心跳检测检测与续约时间
instance:
#告诉服务端,如果我10s之内没有给你发心跳,就代表我故障了,将我剔除掉,默认90s
#Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己)
lease-expiration-duration-in-seconds: 10
#每隔2s向服务端发送一次心跳,证明自已依然活着,默认30s
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则)
lease-renewal-interval-in-seconds: 2
# 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
prefer-ip-address: true
# 实例名称 最后呈现地址:ip:2002
instance-id: ${spring.cloud.client.ip-address}:${server.port}
management:
endpoints:
web:
exposure:
include: ["info","health","refresh"]
2-8、默认如下
访问http://localhost:8881/index
访问http://localhost:8882/index
2-9、修改仓库内容
然后想config server发送POST请求http://localhost:8888/actuator/bus-refresh
2-10、在次访问客户端8881,882显示如下
三、指定刷新范围
在上面案例中我们看到当你触发/actuator/bus-refresh端点时,它就会刷新所有实例的服务配置,有时候我们可能只需要刷新某个具体的实例。
Spring Cloud Bus对这种场景也有很好的支持,/actuator/bus-refresh接口提供了一个 destination参数,RESTFUL风格请求,用来定位具体要刷新的应用程序。比如:我们可以请求/actuator/bus-refresh/customers:8881,此时总线上的各应用实例会根据destination属性的值来判断是否为自己的实例名,若符合才进行配置刷新,若不符合就忽略该消息。
destination参数除了可以定位具体的实例之外,还可以用来定位具体的服务。定位服务的原理是通过使用Spring的PathMatecher(路径匹配)来实现的,比如/actuator/bus-refresh/customers:**,该请求会触发customers服务的所有实例进行刷新。
3-1、以前仓库信息为:
例如:修改为如下
3-2、向http://localhost:8888/actuator/bus-refresh/springcloud-config-client:8882发送POST请求
3-3、访问客户端内容如下
四、总结
使用/actuator/bus-refresh发送到我们其中一个config-client中也能刷新配置(前提是该客户端的bus-refresh端点需要暴露出来),但是这样这个实例就跟其他实例不一样了,它还额外承担了刷新配置的功能。所以,我们将发送post请求刷新配置的任务交由config-server配置服务中心来处理,这样所有服务实例都是对等的,由配置服务中心发送消息通知消息总线更新整个集群中的配置。这样,服务实例就不需要再承担触发配置更新的任务。尽可能让服务集群中的各个节点是对等的将来利于运维工作。