1.什么是Bus为什么需要Bus?
在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有的微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。它一共有两种设计思想。
1.1触发一个客户端进而刷新所有客户端
ConfigClient实例都监听MQ中同一个topic(默认是SpringCloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其它监听同一个Topic的服务就能得到通知,然后去更新自身的配置。如下图所示:
运维人员更新Git仓库里的配置,配置中心从Git仓库中拉取相应的配置文件,下面的微服务再从这个配置中心里面拉取配置文件。之前Config分布式配置中心要想更新需要对每个微服务发送POST请求。这个我们对一个微服务发送POST请求通过Bus消息总线可以在局域网上像传染病一样通知到每一个微服务节点,这个功能是由消息中间件来实现的。SpringCloudBus是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能。目前SpringCloud Bus目前支持RabbitMQ和Kafka。
但是这种方案有他的缺点
- 它打破了为服务职责的单一性,因为微服务本身就是业务模块,它本身不应该承担配置刷新的功能,而且万一有一个服务挂了不但影响他本身的功能而且也没法通知其他的服务修改配置。
- 它破坏了微服务各节点的对等性。假如说AppA具有更新配置功能,B和C没有这样的功能,那么服务之间功能就出现了不平等,假如我想更新A但是我不方便更新B和C,这就会导致集群产生分裂性。
- 有一定的局限性,例如,微服务在迁移时,它的网络地址尝尝会发生变化,此时如果想要做到自动刷新,那就会增加更多的修改。
1.2触发一个服务端进而刷新所有客户端
这种是运维向Config Server发送一个POST请求由这个Config Server,由中心开始广播给其他服务。这种思想才是我们常用的思想,下面我们将介绍这种思想的两种应用,一个是广播通知,一个是定点通知。
2.触发一个服务端进而刷新所有客户端
首先先将Config Server配置好端口号为3344,再配置两个ConfigClient端口分别为3355,3366。来看一下具体的配置。
3344的配置文件。
server:
port: 3344 #端口号
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://gitee.com/wjzmvp/springcloud-config.git #配置文件所在仓库地址
search-paths: #搜索目录
- springcloud-config
label: master #读取分支
#启动成功后访问的路径 http://ip:3344/{label}/{application}-{profile}.yml 能访问的配置文件 就表示成功了
#rabbitmq相关配置
rabbitmq:
host: localhost
port: 15672
username: guest
password: guest
#注册进eureka
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "bus-refresh"
要想暴露监控端点必须得有相应的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后在添加rabbitmq的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
3355,3366由于他们都是客户端所以配置文件大体一样看一个就行了。
server:
port: 3355 #端口号
spring:
application:
name: config-client
cloud:
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述三个综合http://localhost:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心的地址
rabbitmq:
host: localhost
port: 15672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://localhost:7001/eureka #单机版
# 暴露监控端点 否则 curl -X POST "http://localhost:3355/actuator/refresh" 不可使用
management:
endpoints:
web:
exposure:
include: "*"
他们两个唯一不同的是rabbitmq的配置15672是web的管理页面如果两个都配这个的话会报An unexpected connection driver error occured,所以另一个可以配置5672MQ访问的端口这样就不会报错了。
同样客户端服务也需要引入actuator,rabbitmq依赖。
然后我们启动7001eureka,3344,3355,3366分别访问一下看一下现在远程仓库里的配置文件。
3344:
3355:
3366:
现在我们需要达到这样一个效果在仓库上修改一个配置文件,一次修改处处生效,达到广播的效果。
现在我们将gitee仓库的配置文件version改成5,然后我们只刷新3344然后我们期望达到的效果是3355,3366不需要重启就能自动刷新。
刷新之后的结果:
3344:
3355:
3366:
实际结果可以看出我们通过刷新3344配置中心服务端实现了不用重启3355,3366就可以自动更新配置的目的。同时我也不用挨个通知,只通知3344就行了这样就达到了广播的目的。这个的原理就是ConfigClient实例都监听MQ中同一个topic(默认springCloudBus)。
当一个服务刷新数据的时候,他会把这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置。
3.Bus动态刷新之定点刷新(精准打击)
我现在不想全部通知,只想定点通知。 我之前的仓库配置文件的version为5,现在我将它改为7,然后我只通知3355,不通知3366。
这个命令是之前的后面加上/微服务名:端口号。
3355:
3366:
然后我们可以看到当我们定点通知了3355时,3355version变成了7,3366没变还是5。说明只告诉了3355,没告诉3366。