1、介绍
①概念
人话:不用一个一个服务去post。一次post后,各个服务通过bus都能获取post的信息去更新配置。
即将N次向client的post,改为了一次post(向client或center)
在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,让系统里面所有的微服务都连接上来,由于该主题中产生的消息会被所有实例监听和消费,所以称他为消息总线。
在总线上的各个实例,都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。
②原理
ConfigCilent实例都监听MQ中一个Topic,一个服务刷新数据时候,会放入Topic,这样其他监听同一个Topic的服务就能知道了,然后可以更新自己。
不就是消息队列嘛,数据刷新的时候会放入消息队列,Client监听消息队列,然后通过消息获得通知,更新自己的配置
③设计思路/选择
一.通过Client传达
通过消息总线触发一个客户端/bus/refresh
,刷新所有客户端的配置
二.通过ConfigServer传达(使用这个)
利用消息总线,触发一个服务端ConfigServer的/bus/refresh
端点,从而刷新所有的客户端配置
三.选择通过设计二搭建的原因
- 一打破了微服务的职责单一性,因为微服务本身是业务模块,不应该承担配置刷新职责
- 破坏微服务之间的对等性
- 在服务迁移的时候,地址会变化,这时候需要很多更改
2、搭建环境
①搭建RabbitMQ
拉取rabbitMQ的镜像文件:
docker pull rabbitmq:3.8.3-management
运行rabbitmq:
docker run -d -p 5672:5672 -p 15672:15672 --name myRabbitMQ 容器id
访问可视化界面15672端口:
用户名密码都为guest
②搭建另一个Cient
新建项目cloud-config-client-3366
pom.xml:
<dependencies>
<!--config server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--eureka client(通过微服务名实现动态路由)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
bootstrap.yml:
server:
port: 3366
spring:
application:
name: config-client
cloud:
config: #config客户端配置
label: master #分支名称
name: config #配置文件名称 这三个综合:master分支上的config-dev.yml的配置文件
profile: dev #读取后缀名称 被读取到http://config-3344.com:3344/master/config/dev
uri: http://localhost:3344 #配置中心地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka #服务注册到的eureka地址
#暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
启动类:
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3366 {
public static void main(String[] args) {
SpringApplication.run(ConfigClientMain3366.class, args);
}
}
Controller:
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${config.info}") //spring的@Value注解
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return configInfo;
}
}
3、全局广播
①在ConfigCenter上添加BUS支持
添加BUS-rabbitmq依赖:
<!--添加消息总线RabbitMQ的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yml:
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://github.com/zko0/springcloud-config.git #git的仓库地址
search-paths: #搜索目录
- springcloud-config
#如果仓库为私有,需要下面的认证信息
#username: zko0 用户名
#password: xxxxxxx token
label: master #读取的分支
#RabbitMQ相关配置
rabbitmq:
host: #本机写localhost,服务器的写服务器地址
port: 5672 #客户端和RabbitMQ进行通信的端口
username: guest #默认也是guest
password: guest #默认也是guest
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: 'bus-refresh'
②在Client(3355、3366)上添加BUS支持
添加bus-rabbitmq依赖:
<!--添加消息总线RabbitMQ的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yml:
spring:
application:
name: config-client
cloud:
config: #config客户端配置
label: master #分支名称
name: config #配置文件名称 这三个综合:master分支上的config-dev.yml的配置文件
profile: dev #读取后缀名称 被读取到http://config-3344.com:3344/master/config/dev
uri: http://localhost:3344 #配置中心地址
rabbitmq:
host: 101.43.244.40 #本机写localhost,服务器的写服务器地址
port: 5672 #客户端和RabbitMQ进行通信的端口
username: guest #默认也是guest
password: guest #默认也是guest
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka #服务注册到的eureka地址
#暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
③测试
启动ConfigServer3344,Clinet3355,3366,测试,正常:
修改仓库中的config-dev配置,将version改为5
一段时间后,Config Center动态更新配置,version更新为5,此时Client的version仍为4:
向Config Center发送Post请求,url为:
http://localhost:3344/actuator/bus-refresh
此时查看Client3355,和Client3366,version都已经刷新为5,测试成功:
4、定点通知
①概念
如果我们只想通知3355刷新配置,3366不刷新呢?
方法:
http://配置中心ip:端口号/actuator/bus-refresh/{通知目标}
/bus/refresh
请求不再发送到具体的服务实例上,而是发给config server并通过destination参数类指定需要更新配置的服务或实例
如只通知3355不通知3366:
http://localhost:3344/actuator/bus-refresh/config-client:3355
②实测
修改配置文件,version为6
Config Center的version更新为6
发送post请求,只通知3355更新配置:
由下图可见config-client的实例和端口3355
发送请求:
http://localhost:3344/actuator/bus-refresh/config-client:3366
查看Client3355,和Client3366,成功: