开始配置中心前,先模拟一个业务场景:电商系统做一次促销活动,由于无法预估促销商品的需求量,于是设置了库存为100个,研发工程师可能在代码中写死库存总数为100,由于销售火爆,100个库存无法满足人们的需求,想加大库存,那么研发工程师需要修改代码,走测试流程,再发布到正式环境,一个小参数的改动却要花费大量重复时间。于是通过代码重构,可以把这个库存参数写到远程配置中(本地静态配置运行时无法动态修改生效),定时获取配置信息,下次做促销活动时,快速调整库存,这是配置中心能提供的功能。
配置中心的真实场景还能做很多事情,如:根据网站的实时流量调整限流参数,扩大线程池大小,开启-关闭新功能,线上功能调式等
市面上开源的配置中心有很多,BAT每家都出过,360的QConf、淘宝的diamond、百度的disconf都是解决这类问题,Spring Cloud全家桶中就有 Spring Cloud Config组件,利用 git 服务与 rabbitmq ,通过消息总线实现动态配置,它有以下特性:
- 提供服务端和客户端支持(服务端把配置文件拉取后存储在本地,客户端通过接口获取服务端拉下来的数据)
- 集中管理配置文件
- 配置文件修改之后,可快速生效
- 支持较大并发查询
本篇要分享的内容:Spring Cloud Config + Spring Cloud Bus + RabbitMQ 实现配置中心配置动态更新,当在 Git 仓库中某个应用配置文件中的参数更新后,只需要通过Git的 WebHook 发送 POST请求到 config Server 的 /actuator/bus-refresh 接口,通过消息总线通知rabbitmq,让所有的客户端服务实例更新配置
1.项目依赖环境
- 1.需要 git 仓库,且创建个spring-config-repo的项目,并添加配置文件(对应开发、测试、正式环境),内容如图,这是我的示例仓库与文件内容
- 2.rabbitmq环境,rabbitmq安装教程
- 3.eureka 注册中心
- 4.两个项目,config-server服务端、config-client客户端,当git上的配置文件修改时,server端会拉取配置信息到本地,client端会取server端的信息
- 5.要达到目标:外部配置文件集中放置在一个git仓库里,用来管理所有的配置文件,维护的时候需要更改配置时,只需要在本地更改后,推送到远程仓库,所有服务实例都可以通过config server来获取配置文件,当有配置更新时通过 Git 的 WebHook 发送 Post 请求,调用 config-server 暴露的 /actuator/bus-refresh 刷新端点,通过消息总线去动态刷新 config-client 的配置
2.代码实践
- 1.启动 eureka 注册中心
- 2.新建 config-server 项目,添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<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.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 3.在config-server的启动类上添加注解,启用配置服务与服务注册发现
@EnableConfigServer
@EnableDiscoveryClient
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
- 4.给config-server添加配置两个文件,bootstrap.yml与application.yml,注意:bootstrap.yml的配置先加载
# bootstrap.yml
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
# application.yml
# config-server会在本地的临时目录下克隆远程仓库中的信息,默认保存在本机:C:\Users\zhuyu\AppData\Local\Temp\config-repo-315688083391782199\config-info
# 可更改本地仓库clone的配置文件信息的路径 spring.cloud.config.server.git.basedir=D:\\localGitRepo\\
server:
port: 2000
spring:
application:
name: config-server
cloud:
bus:
trace:
enabled: true
config:
server:
git:
uri: https://gitee.com/zhuyu1991/spring-config-repo.git # git仓库的地址
searchPaths: config-info # git仓库地址下的相对地址,可以配置多个,用,分割
username: 用户名 # git仓库的账号
password: 密码 # git仓库的密码
rabbitmq:
host: 192.168.1.101
port: 5672
username: 用户名
password: 密码
virtual-host: zy_vhosts
# 注册中心配置
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://zy:zy123@localhost:10025/eureka/
- 5.访问 http://localhost:2000/config-info/dev ,看到以下内容,说明config-server端搭建成功了,红色框框内容的是远程 git 仓库中的配置信息
- 6.新建 config-client 项目,添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 7.在config-client的启动类上添加注解,启用服务注册发现@EnableDiscoveryClient
- 8.给config-client添加配置两个文件,bootstrap.yml与application.yml,注意:bootstrap.yml的配置先加载,一定要在bootstrap.yml中先配置 config-server的地址,不然无法获取server端的配置信息
# bootstrap.yml
spring:
cloud:
bus:
trace:
enabled: true
config:
label: master # label代表要请求那个git分支
#uri: http://localhost:2000 # uri代表config-server的地址,可指定地址
name: config-info # name代表请求那个名称的远程文件,与confif-server的searchPaths对应,可以写多个,逗号分隔
profile: dev # profile代表那个分支文件,如:dev 、 test 、 prod
# 这里基于服务发现,不指定uri
discovery:
enabled: true
service-id: config-server
# 注册中心配置
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://zy:zy123@localhost:10025/eureka/
# application.yml
server:
port: 2002
spring:
application:
name: config-client
rabbitmq:
host: 192.168.1.101
port: 5672
username: 用户名
password: 密码
virtual-host: zy_vhosts
- 9.添加一个 IndexController 控制器,用来返回配置信息,注意@RefreshScope注解,只有添加这个注解才能运行时刷新,内容如下:
@RestController
@RefreshScope
public class IndexController {
// 配置远程 git 仓库中配置文件的 key,且设置个默认值
@Value("${springcloud.book.config:123}")
private String book;
@RequestMapping("/getBookConfig")
public String getBookConfig(){
return book;
}
}
- 10.远程git仓库中的配置文件内容
- 11.启动 config-client 项目,访问 http://localhost:2002/getBookConfig ,说明 config-client 取到 config-server端的内容了
- 12.修改git仓库中配置文件的内容,访问 config-server端,能看到配置信息更新了,但 config-client 端的内容依旧是之前的,此时需要通过发送 Post 请求 http://localhost:2000/actuator/bus-refresh,来触发刷新配置
- 13.再访问 http://localhost:2002/getBookConfig ,可看到配置已经刷新了
好了,Spring Cloud Config 做配置中心的功能分享到这里,它需要依赖 spring-cloud-starter-bus-amqp 消息队列总线 和 spring-boot-starter-actuator 暴露刷新接口,以及 @RefreshScope 注解共同完成刷新操作
需要注意的是有两个配置文件,配置文件加载的先后顺序要注意,bootstrap.yml里面的内容要先加载
代码已上传至码云:
项目版本信息如下:
- SpringBoot 2.0.6.RELEASE
- SpringCloud Finchley.SR2
中小型项目使用Spring Cloud 全家桶提供的配置中心解决方案还行,它优点是开箱即用、简单,缺点是没有配置界面,容易出错,团队间不好协同,针对这种情况,携程开源了 Apollo 配置中心,在 GitHub 上超过 11K 颗星,很多大厂都采用了它作为生产环境的配置中心,地址:https://github.com/ctripcorp/apollo