目录
bus
简介
从 上一篇 文章可以得知 config client
服务从 config server
端获取自己对应的配置文件,但是目前的问题是:当远程 git
仓库配置文件发生改变时,每次都是需要重启 config client
服务,如果有上百上千个微服务呢?
我想我们不会一个个去重启每个微服务,也就是说如何让 config server
端通知到 config client
端?
即 config client
端如何感知到配置发生更新?
这时候就该 bus
上场了,使用 springcloud bus
(国人很形象的翻译为消息总线)可以完美解决这一问题
bus
工作架构
大家可以将它理解为管理和传播所有分布式项目中的消息既可,其实本质是利用了 MQ
的广播机制在分布式的系统中传播消息,目前常用的有 Kafka
和 RabbitMQ
。利用 bus
的机制可以做很多的事情,其中配置中心客户端刷新就是典型的应用场景之一,我们用一张图来描述 bus
在配置中心使用的机制
- 提交配置触发
post
请求给server
端的bus/refresh
接口 server
端接收到请求并发送给springcloud bus
总线springcloud bus
接到消息并通知给其它连接到总线的客户端- 其它客户端接收到通知,请求
server
端获取最新配置 - 全部客户端均获取到最新的配置
它的特点:config
配置中心 server
端承担起配置刷新的职责
bus
消息总线的实现
项目结构依然使用上一篇的,如下
config
配置中心服务端
Maven
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
application.properties
配置文件
完整配置如下,主要增加了 rabbitmq
的配置与健康检查
server.port=8070
#注册进eureka的名称
spring.application.name=eureka-client-config
eureka.client.service-url.defaultZone=http://eureka7001:8761/eureka/
eureka.instance.prefer-ip-address=true
#gitee的仓库地址
spring.cloud.config.server.git.uri=https://gitee.com/chaojiangcj/springcloud-learn-config.git
spring.cloud.config.server.git.username=你的用户名
spring.cloud.config.server.git.password=你的密码
#配置仓库需要找的文件路径
spring.cloud.config.server.git.search-paths=eureka-client-*
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#健康检查
management.endpoints.web.exposure.include=*
config
配置中心客户端
Maven
添加依赖
eureka-client-consumer,eureka-client-producer
两个项目都要引入
<!--springcloud bus消息总线-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--使用springboot的健康检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
远程 git
仓库配置文件
eureka-client-consumer
完整配置如下,增加了 rabbitmq
的配置
spring.profiles.active=dev
server.port=8090
#注册进eureka的名称
spring.application.name=eureka-client-consumer
eureka.client.service-url.defaultZone=http://eureka7001:8761/eureka/
eureka.instance.prefer-ip-address=true
#Feign默认整合了Hystrix,要想为Feign打开Hystrix支持,需要此项设置
#在springcloud Dalston之前的版本中,Feign默认开启Hystrix支持,无需设置feign.hystrix.enabled=true
#从springcloud Dalston版本开始,Feign的Hystrix支持默认关闭,需要手动设置开启
feign.hystrix.enabled=true
#配ribbon的超时时间,默认二者都是1000
#ribbon.ConnectTimeout=2000
#ribbon.ReadTimeout=2000
#第一次启动时,请求接口查询数据库有点耗时,会进入降级策略,所以将hystrix的超时时间设置为3s,默认是1s,这是全局设置
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#自定义配置,用于测试
congfig.version=config-version 1.0
eureka-client-producer
完整配置如下,增加了 rabbitmq
的配置
server.port=8080
#注册进eureka的名称
spring.application.name=eureka-client-producer
#JDBC 配置
spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTC
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#druid 连接池配置
spring.datasource.druid.initial-size=3
spring.datasource.druid.min-idle=3
spring.datasource.druid.max-active=10
spring.datasource.druid.max-wait=60000
#指定 mapper 文件路径
mybatis.mapper-locations=classpath:org/example/mapper/*.xml
mybatis.configuration.cache-enabled=true
#开启驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
#打印 SQL 语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
eureka.client.service-url.defaultZone=http://eureka7001:8761/eureka/
eureka.instance.prefer-ip-address=true
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
添加 @RefreshScope
注解
该注解我们添加在 eureka-client-consumer
项目的 controller
层,增加了一个测试接口,如下
@RefreshScope
@Slf4j
@Controller
@RequestMapping(path = "/UserConsumer")
public class UserConsumerController {
@Autowired
private UserConsumerService userConsumerService;
@Value(value = "${congfig.version}")
private String configVersion;
/**
* ribbon 实现负载均衡
*/
@GetMapping(path = "/findOneById")
@ResponseBody
public ResultVo findOneById(Integer id) {
return userConsumerService.findOneById(id);
}
/**
* feign 进行远程调用
*/
@GetMapping(path = "/queryOneById")
@ResponseBody
public ResultVo queryOneById(@RequestParam(name = "id") Integer id) {
return userConsumerService.queryOneById(id);
}
/**
* 测试springcloud bus获取配置
*/
@GetMapping(path = "/getConfigVersion")
@ResponseBody
public String getConfigVersion() {
log.info("configVersion的值为:" + configVersion);
return configVersion;
}
}
- 自动刷新只能刷新
@RefreshScope
注解下的配置,一些特殊配置,如数据库等,需要同样先设置数据库链接ConfigServer
类,然后通过加@RefreshScope
注解方式自动刷新
/bus-refresh
接口
要实现配置自动刷新,需要调用 /bus-refresh
接口通知 config server
端,有两种方式
- 手动调用(
post
请求):http://ip:port/actuator/bus-refresh
(config server
端地址) - 配置
git
的webhook
,当git
端配置发生改变,自动调用/bus-refresh
接口
测试
分别启动 rabbitmq
,eureka-client-consumer
,eureka-client-producer
,eureka-client-config
以及 eureka
的服务端项目
测试一
启动上述服务之后,首先来请求接口 http://127.0.0.1:8090/UserConsumer/getConfigVersion
获取这个变量
测试二
修改变量如下
再次请求接口 http://127.0.0.1:8090/UserConsumer/getConfigVersion
获取这个变量,如下
测试三
- 首先请求接口
http://127.0.0.1:8070/actuator/bus-refresh
(config
服务端的ip,port
),注意是post
请求方式。它什么都没有返回
- 这里看看请求
http://127.0.0.1:8070/actuator
接口,它返回了健康监控的一些信息,如下
- 再一次请求接口
http://127.0.0.1:8090/UserConsumer/getConfigVersion
获取这个变量,如下
- 同时,看
rabbitmq
的管理页面,创建的交换机如下
创建的队列如下