13-SpringCloud Config
SpringCloud Config
概述
什么是配置中心
对于传统的单体应用而言,常使用配置文件来管理所有配置,比如SpringBoot的application.yml文件,但是在微服务架构中全部手动修改的话很麻烦而且不易维护。微服务的配置管理一般有以下需求:
- 集中配置管理,一个微服务架构中可能有成百上千个微服务,所以集中配置管理是很重要的。
- 不同环境不同配置,比如数据源配置在不同环境(开发,生产,测试)中是不同的。
- 运行期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池大小等
- 配置修改后可自动更新。如配置内容发生变化,微服务可以自动更新配置
综上所述对于微服务架构而言,一套统一的,通用的管理配置机制是不可缺少的总要组成部分。常见的做法就是通过配置服务器进行管理。
常见的有:
- 携程的阿波罗Apollo
- 百度的Disconf
简介
Spring Cloud Config 项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。
Spring Cloud Config 为分布式系统中的外部配置提供服务器和客户端支持。使用ConfigServer,可以为所有环境中的应用程序管理其外部属性。它非常适合spring应用,也可以使用在其他语言的应用上。随着应用程序通过从开发到测试和生产的部署流程,您可以管理这些环境之间的配置,并确定应用程序具有迁移时需要运行的一切。服务器存储后端的默认实现使用git
,因此它轻松支持标签版本的配置环境,以及可以访问用于管理内容的各种具。
Spring Cloud Config服务端特性:
- HTTP,为外部配置提供基于资源的API(键值对,或者等价的YAML内容)
- 属性值的加密和解密(对称加密和非对称加密)
- 通过使用
@EnableConfigServer
在Spring boot应用中非常简单的嵌入。
Config客户端的特性(特指Spring应用)
- 绑定Config服务端,并使用远程的属性源初始化Spring环境。
- 属性值的加密和解密(对称加密和非对称加密)
入门
准备工作
ConfigServer是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git
存储配置文件内容,也可以使用SVN存储,或者是本地文件存储。
(1)新建仓库(Gitee)
(2)创建仓库:config-repostory
(3)上传配置文件,将product_service
工程的 application.yml 改名为 product-dev.yml 后上传
(4)文件命名规则:
- {application}-{profifile}.yml
- {application}-{profifile}.properties
- application为应用名称 ,profifile指的开发环境(用于区分开发环境,测试环境、生产环境等)
搭建服务端程序
config_server 工程
引入坐标
<!--引入config-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
配置启动类
@SpringBootApplication
@EnableConfigServer //开启配置中心服务端功能
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class,args);
}
}
yml文件创建并配置
#====================
# config基础配置
# 只需要引入 spring-cloud-starter-config 依赖即可
#====================
server:
port: 9999 #服务端口
spring:
application:
name: config-server #指定服务名
cloud:
config:
server:
git:
uri: https://gitee.com/geekhwx/config-repostory.git
访问测试
启动工程,浏览器输入 http://localhost:9999/{仓库中的文件名}
搭建客户端程序
product_service 工程
引入坐标
<!--引入config-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
yml文件创建并配置
- 因为application.yml 已经放在了git上,因此需要创建一个加载级别高的
bootstrap.yml
文件,进行读取git内容 - 删除当前工程下的 application.yml
#====================
# 基础配置
# 从config-server中获取配置信息
#====================
spring:
cloud:
#config 配置
config:
name: product #应用名称,需要对应git中配置文件名称的前半部分
profile: pro #切换开发/测试环境
label: master #git中的分支
uri: http://localhost:9999/ #config-server的请求地址
启动类配置
- 不用做修改
@SpringBootApplication
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
访问测试
-
依次启动Eureka、config、product
-
product中配置dev环境时访问:http://localhost:9001/product/name
-
product中配置pro环境时访问:http://localhost:9002/product/name
可以根据配置的不同,读取到码云仓库中不同的配置文件
手动刷新缓存
product_service 工程
问题描述
有时候更改了git上的文件,config-server端可以实时获取,但是product_service客户端是将数据缓存到本地,所有不是实时数据,此时就需要改造product_service端的配置
环境搭建
引入坐标
<!--引入端点检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
修改yml配置
#开启动态刷新的请求路径端点
management:
endpoints:
web:
exposure:
include: refresh
修改controller,增加 @RefreshScope
注解
@RestController
@RequestMapping(value = "/product")
@RefreshScope //开启动态刷新
public class ProductController {
...
}
访问测试
-
先访问第一次,http://localhost:9001/product/name 返回 hwx-dev-23333333
-
修改码云仓库中文件的属性值为 hwx-dev
-
再访问第二次,http://localhost:9001/product/name 返回返回依旧是 hwx-dev-23333333
-
因此必须刷新配置,才可以得到最新数据
-
启动postman软件,必须为POST请求,发送psot请求到9001或9002的端口,http://localhost:9001/actuator/refresh
- 再次浏览器访问 http://localhost:9001/product/name ,此时已读取到最新实时数据,hwx-dev
高可用
config_server工程
服务端改造
引入坐标
<!--引入EurekaClient-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--引入config-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--引入端点检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yml配置
- 添加eureka配置
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true #使用ip地址注册
启动类添加注解
@SpringBootApplication
@EnableConfigServer //开启配置中心服务端功能
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class,args);
}
}
idea 复制应用
准备两个config服务端( 9999,9992 ),copy一个应用,修改端口号配置 -Dserver.port=9992
客户端改造
product_service 工程
修改yml配置
- 开启 动态刷新的请求路径端
spring:
cloud:
config:
name: product #应用名称,需要对应git中配置文件名称的前半部分
profile: pro #开发环境
label: master #git中的分支
# uri: http://localhost:9999/ #config-server的请求地址,此时不需要是有固定的路径
#通过注册中心获取config-server配置
discovery:
enabled: true #开启服务发现
service-id: config-server #服务名称
#开启动态刷新的请求路径端点
management:
endpoints:
web:
exposure:
include: refresh
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/ #多个eurekaserver之间用,隔开
instance:
prefer-ip-address: true #使用ip地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id
- 自相矛盾的一点是,此时还需要配置eureka
- 是因为,product需要使用eurekafa访问config,从而得到码云上的文件,码云仓库中包含了eureka,但是前提是product需要先连上eureka才可以去访问config,因此此处矛盾在码云中包含eureka,但本地也照样需要配置eureka
访问测试
-
依次启动Eureka、config、product
-
product中配置dev环境时访问:http://localhost:9001/product/name
-
product中配置pro环境时访问:http://localhost:9002/product/name
可以根据配置的不同,读取到码云仓库中不同的配置文件
消息总线bus
在微服务架构中,通常会使用轻量级的消息代理来构建一个共用的消息主题来连接各个微服务实例,它广播的消息会被所有在注册中心的微服务实例监听和消费,也称消息总线。SpringCloud中也有对应的解决方案,SpringCloud Bus 将分布式的节点用轻量的消息代理连接起来,可以很容易搭建消息总线,配合SpringCloud config 实现微服务应用配置信息的动态更新。
根据此图我们可以看出利用Spring Cloud Bus做配置更新的步骤:
- 提交代码触发post请求给bus/refresh
- server端接收到请求并发送给Spring Cloud Bus
- Spring Cloud bus接到消息并通知给其它客户端
- 其它客户端接收到通知,请求Server端获取最新配置
- 全部客户端均获取到最新的配置
消息总线整合配置中心
config服务端改造
引入坐标
<!--引入消息总线bus-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<!--引入RebbitMQ-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
yml配置
server:
port: 9999 #服务端口
spring:
application:
name: config-server #指定服务名
cloud:
config:
server:
git:
uri: https://gitee.com/geekhwx/config-repostory.git
rabbitmq:
addresses: 127.0.0.1
username: guest
password: guest
#开启动态刷新的请求路径端点,post访问 http://localhost:9999/actuator/bus-refresh 进行刷新
management:
endpoints:
web:
exposure:
include: bus-refresh
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/ #多个eurekaserver之间用,隔开
instance:
prefer-ip-address: true #使用ip地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id
- 增加 management 的配置
微服务客户端配置
引入坐标
<!--引入消息总线bus-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<!--引入RebbitMQ-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
yml配置
spring:
cloud:
config:
name: product #应用名称,需要对应git中配置文件名称的前半部分
profile: pro #开发环境
label: master #git中的分支
#通过注册中心获取config-server配置
discovery:
enabled: true #开启服务发现
service-id: config-server #服务名称
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/ #多个eurekaserver之间用,隔开
instance:
prefer-ip-address: true #使用ip地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id
- 移除 management 的配置
git仓库中,向配置文件中添加rabbitmq的配置信息
rabbitmq:
addresses: 127.0.0.1
username: guest
password: guest
访问测试
-
重新启动对应的eureka-server , config-server , product-service。若git上配置信息更新后,只需要向配置中心发送对应的请求,即可刷新每个客户端的配置
-
post访问 http://localhost:9999/actuator/bus-refresh 进行刷新配置