配置中心的痛点
我们知道SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置,但是它无法很方便的实现多客户端的配置一键刷新
,现在使用springcloud Bus 配合 springcloud Config 可以实现配置的动态刷新,达到一次通知,处处生效的效果。
什么是总线
在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线
。在总线上的各个实例,都可以方便地广播-些需要让其他连接在该主题上的实例都知道的消息。
关于springcloud Bus
Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能。Spring Clud Bus目前支持RabbitMQ
和Kafka
。SpringCloud Bus能管理和传播分布式系统间的消息,就像一个分布式执行器,可用于广播状态更改、事件推送等,也可以当作微服务的通信通道。Bus支持如下两种广播方式:
方式一
通知客户端再蔓延:
Bus直接通知给其中⼀个客户端,由这个客户端开始蔓延,传播给其他所有客户端
方式二
通知服务端再广播
通知给配置中⼼的服务端,由服务端⼴播给所有客户端
相比这两种方式,
方式二
我觉得会更加合适,因为方式一打破了微服务的职责单一性,因为微服务本身是业务模块,它本不应该承担配置刷新的职责。破坏了微服务各节点的对等性。因为第一种,有一个客户端需要额外的承担刷新职责,而其他的客户端却只有业务职责有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就会增加更多的修改。
使用SpringCloud Bus
SpringCloud Bus目前支持的消息代理有
RabbitMQ
和Kafka
,在这里我选择的是使用RabbitMQ
并且选择方式二
来进行配置更新通知
基本环境
- 注册中心,我这里使用的是
Eureka
- 安装
RabbitMQ
服务端配置
添加依赖
<!--config server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- 添加消息总线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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改application.yml
server:
port: 7070
spring:
application:
name: cloud-config-server
# config 配置
cloud:
config:
server:
git:
uri: https://github.com/martaintao/spring-config-center-demo.git # 因为我这个是public的仓库,所以不需要认证。
label: master
# rabbitmq 配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# eureka注册中心配置
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册消息,默认为true,单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
defaultZone: http://localhost:8080/eureka/
# 配置暴端点
management:
endpoints:
web:
exposure:
include: 'bus-refresh' # 暴露端点
启动类
使用
@EnableConfigServer
注解来开启配置服务
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigCenterApplication7070 {
public static void main(String[] args) {
SpringApplication.run(ConfigCenterApplication7070.class,args);
}
}
客户端配置
添加依赖
<!-- 添加消息总线RabbitMQ支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!-- spring config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</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>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改 bootstrap.yml
注意,这里是创建
bootstrap.yml
,这个配置⽂件的作⽤是,先到配置中⼼加载配置,然后加载到application.yml
中。
application.yml
是用户级的资源配置项。
bootstrap.yml
是系统级的,优先级比application.yml
更高。
server:
port: 7001
spring:
application:
name: cloud-eureka-consumer-useradmin
cloud:
config:
label: master # 分支名称
name: config # 配置文件名称 列如config-dev.yml 名称就是config
profile: dev # 环境(读取后缀)
uri: http://127.0.0.1:7070 # 配置中心地址
# rabbitMQ 配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# 注册中心配置
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册消息,默认为true,单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
defaultZone: http://localhost:8080/eureka/
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
测试接口
直接访问
/getConfigInfo
来获取远程配置文件中的config.info
信息
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/getConfigInfo")
public String getConfigInfo(){
return configInfo;
}
}
启动类
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientApplication7001 {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication7001.class,args);
}
}
测试
先启动注册中心和RabbitMQ,然后再启动配置服务端以及客户端。
- 1、查看远程仓库的
config-dev.yml
config:
info: "dev config"
- 2、请求服务端
GET http://localhost:7070/master/config-dev.yml
config:
info: dev config
- 3、请求客户端
/getConfigInfo
dev config
- 4、更改远程仓库的
config-dev.yml
config:
info: "dev config I already change it"
- 5、请求服务端
GET http://localhost:7070/master/config-dev.yml
config:
info: dev config I already change it
- 6、请求客户端
/getConfigInfo
dev config
这里我们可以看到,客户端的配置还是没有刷新,我们需要发送一个指令给服务端,让服务端广播配置更改的通知
- 7、发送指令给服务端
(POST /actuator/bus-refresh)
POST http://localhost:7070/actuator/bus-refresh
1
- 8、检查客户端配置
/getConfigInfo
dev config I already change it
到这里发现已经应用了最新的配置了。如果有多台客户端绑定该配置中心的话,只需要通知一次即可让所有的客户端更新最新配置。
定点通知
刚刚我们演示了方式二,发送指令给配置中心服务,然后所有的客户端都全部更新,但是有的时候我们可能只希望更改其中的一部分客户端而已,是否可以指定呢?答案是肯定的。
我们知道了发送POST请求/actuator/bus-refresh
给服务端会让所有的客户端都应用最新配置。我们可以在后面指定某个客户端。比如:
POST http://localhost:7070/actuator/bus-refresh/cloud-eureka-consumer-useradmin:7001
如上就会通知微服务名为cloud-eureka-consumer-useradmin
且端口号为7001
的服务进行更新。由此我们也知道了指定方式是 微服务名称+端口号
来源:https://www.jianshu.com/p/2c58ed88922d
文章评论