概述
分布式系统面临的配置问题
微服务意味着要将单体应用中的业务拆分成一个个的子业务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。
Spring Cloud提供了ConfigServer来解决这个问题,我们每一个微服务自己带着一个application.yml,上百个配置文件的管理很繁琐。
简介
SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用 的所有环境提供了一个中心化的外部配置。
SpringCloud Config分为客户端和服务端量部分。
服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等的访问接口。
客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。
功能与作用
- 集中管理配置文件
- 不同环境不同配置,动态化配置更新,分环境部署比如dev/test/prod/beta/release
- 运行期间动态调整配置,不在需要在每个服务器部署的机器上编写配置文件,服务会向配置中兴统一拉取配置自己的信息
- 当配置发生变动时,服务不需要重启即可感知到配置的变化,并应用新的配置
- 将配置的信息以REST接口的形式暴露
与GitHub整合配置
由于SpringCloud Config默认使用Git来存储配置文件(也有其他方式,比如支持SVN和本地文件),但最推荐的还是Git,而且使用的是http/https访问的形式。
Config服务端配置
在github上新建仓库
springcloud-config
新建Module
cloud-config-center3344
pom.xml
<dependencies>
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<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>
application.yml
server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: git@github.com/JunqiangLi/springcloud-config.git #GitHub上面的git仓库名字
####搜索目录
search-paths:
- springcloud-config
####读取分支
label: master
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
主启动类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableConfigServer
public class ConfigMain3344 {
public static void main(String args[]){
SpringApplication.run(ConfigMain3344.class, args);
}
}
修改host
在windows/System32/driver/etc/host问价中
尾部添加127.0.0.1 config-3344.com
测试
通过访问下面的地址,检测是否连接至git
http://config-3344.com:3344/master/config-dev.yml
配置读取规则
/{label}/{application}-{profile}.yml
- master分支
- http://config-3344.com:3344/master/config-dev.yml
- http://config-3344.com:3344/master/config-test.yml
- http://config-3344.com:3344/master/config-prod.yml
- http://config-3344.com:3344/master/config-dev.yml
- dev分支
- http://config-3344.com:3344/dev/config-dev.yml
- http://config-3344.com:3344/dev/config-test.yml
- http://config-3344.com:3344/dev/config-prod.yml
- http://config-3344.com:3344/dev/config-dev.yml
- master分支
{application}-{profile}.yml
- http://config-3344.com:3344/config-dev.yml
- http://config-3344.com:3344/config-test.yml
- http://config-3344.com:3344/config-prod.yml
- http://config-3344.com:3344/config-xxxx.yml
- http://config-3344.com:3344/config-dev.yml
{application}/{profile}/{label}
- http://config-3344.com:3344/config/dev/master
- http://config-3344.com:3344/config/test/master
- http://config-3344.com:3344/config/prod/master
- http://config-3344.com:3344/config/xxxx/master
总结
{label}-{name}-{profiles}.yml
label:分支(branch)
name:服务名
profiles:环境(dev/test/prod)
Config客户端配置
新建Moudle
cloud-config-client-3355
pom.xml
注意,此处引入的是spring-cloud-starter-config
,服务端引入的是spring-cloud-starter-config-server
<dependencies>
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<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
说明
application.yml是用户级的资源配置项
bootstrap.yml是系统级的,优先级更高。
SpringCloud会创建一个“Bootstrap Context”,作为Spring应用的“Application Context”的父上下文。初始化的时候,“Bootstrap Context”负责从外部加载配置属性并解析配置。着两个上下文共享一个从外部获取的“Environment”。
“Boostrap”属性有高优先级,默认情况下,他们不会被本地配置覆盖。“Bootstrap Context”和“Application Context”有着不同的约定,座椅新增了一个“boostrap.yml”文件,保证“Boostrap Context”和“Application Context”配置的分离。
要将Client模块下application.yml文件改为bootstrap.yml,这是很关键的,因为bootstrap.yml是比application.yml先加载。
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
启动类
@EnableEurekaClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class ConfigClientMain3355 {
public static void main(String args[]){
SpringApplication.run(ConfigClientMain3355.class,args);
}
}
业务类
@RestController
@Slf4j
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo()
{
return configInfo;
}
}
测试
http://localhost:3355/configInfo
Config客户端之动态刷新
避免每次更新配置都要重启客户端3355
pom引入actuator
监控
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yml暴露监控端点
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
业务类添加注解
@RefreshScope
自动获取刷新的内容
@RestController
@Slf4j
@RefreshScope
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo()
{
return configInfo;
}
}
测试
此时改变GitHub上的配置,通过3344访问,返回结果是改变后的,但是,3355还未改变,为何?
重启之后必须发送一次post请求至3355,配置才可以生效。
在cmd窗口发送
curl -X POST "http://localhost:3355/actuator/refresh"
此时再去测试3355端口,配置生效。
缺陷
假如有多个微服务客户端,每个客户端都要发送一次post请求,手动刷新过于繁琐,可不可以广播,一次通知,处处生效?引入***消息总线***。