文章目录
1. 分布式配置中心应用场景
往往,我们使用配置文件管理一些配置信息,比如application.yml
单体应用架构,配置信息的管理、维护并不会显得特别麻烦,手动操作就可以,因为就一个工程;
微服务架构,因为我们的分布式集群环境中可能有很多个微服务,我们不可能一个一个去修改配置然后重启生效,在一定场景下我们还需要在运行期间动态调整配置信息,比如:根据各个微服务的负载情况,动态调整数据源连接池大小,我们希望配置内容发生变化的时候,微服务可以自动更新。
场景总结如下:
1)集中配置管理,一个微服务架构中可能有成百上千个微服务,所以集中配置管理是很重要的(一次修改、到处生效)
2)不同环境不同配置,比如数据源配置在不同环境(开发dev,测试test,生产prod)中是不同的
3)运行期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池大小等配置修改后可自动更新
4)如配置内容发生变化,微服务可以自动更新配置
那么,我们就需要对配置文件进行集中式管理,这也是分布式配置中心的作用。
2. SpringCloud Config
2.1 Config简介
SpringCloud Config是一个分布式配置管理方案,包含了 Server端和 Client端两个部分。
- Server 端:提供配置文件的存储、以接口的形式将配置文件的内容提供出去,通过使用@EnableConfigServer注解在 SpringBoot 应用中非常简单的嵌入
- Client 端:通过接口获取配置数据并初始化自己的应用
2.2 Config的使用
说明:Config Server是集中式的配置服务,用于集中管理应用程序各个环境下的配置。 默认使用Git存储配置文件内容,也可以SVN。
比如,我们要对“静态化微服务或者商品微服务”的application.yml进行管理(区分开发环境(dev)、测试环境(test)、生产环境(prod))
在git仓库中提交goods-service服务的配置文件 goods-service-dev.properties
命名规则:服务名称-profile名称(dev/test/prod).properties或yml
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/eshop?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
2.2.1 搭建Config服务器
1) 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2)启动类添加注解 @EnableConfigServer @EnableDiscoveryClient
3)配置
server.port=6666
spring.application.name=config-server
#是否从注册中心获得数据
eureka.client.fetch-registry=true
#是否注册到注册中心上
eureka.client.register-with-eureka=true
#配置注册中心的地址
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8888/eureka/
#配置中心git相关配置
spring.cloud.config.server.git.uri=自己的git仓库
spring.cloud.config.server.git.username=自己的账号
spring.cloud.config.server.git.password=自己的密码
#配置文件存放的目录,如果是根目录可以不配置
#spring.cloud.config.server.git.search-paths=xxx
#分支名称
spring.cloud.config.label=master
2.2.2 搭建Config客户端
1) 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
2)将配置文件application改名为bootstrap(bootrap提前于application加载)
server.port=8011
#应用程序名
spring.application.name=goods-service
#是否从注册中心获得数据
eureka.client.fetch-registry=true
#是否注册到注册中心上
eureka.client.register-with-eureka=true
#配置注册中心的地址
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8888/eureka/
#配置中心服务器的配置
spring.cloud.config.discovery.service-id=config-server
#启动配置中心的发现机制
spring.cloud.config.discovery.enabled=true
#配置profile 不写profile 填default
spring.cloud.config.profile=dev
#配置分支
spring.cloud.config.label=master
3) 注入配置内容
@Value("${spring.datasource.driver-class-name}")
private String driverName;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
3. 动态更新配置
配置文件更新后,在不重启系统的基础上,客户端需要获得最新的配置
3.1 手动更新
1)客户端引入依赖 actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2)在需要进行动态更新配置的类上加 @RefreshScope
3)开启端点
#开启全部端点
management.endpoints.web.exposure.include=*
4)发送post请求
http://服务ip:端口/actuator/refresh
3.2 自动更新
自动更新流程
1)在Gitee上配置Webhoock
2)使用内网穿透工具natapp或cpolar等进行测试
3)在启动类上加上@ServletComponentScan注解,并编写自定义的请求包装器和过滤器
/**
* 请求包装器
*/
public class CustomRequestWrapper extends HttpServletRequestWrapper {
public CustomRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
byte[] bytes = new byte[0];
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return byteArrayInputStream.read() == -1 ? true : false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}
}
/**
* 过滤器
*/
@WebFilter(filterName = "bodyFilter", urlPatterns = "/*")
@Order(1)
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String url = new String(httpServletRequest.getRequestURI());
//只过滤/actuator/refresh请求
if (!url.endsWith("/actuator/refresh")) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
}
@Override
public void destroy() {
}
}
3.3 使用消息总线Bus+RabbitMQ实现自动更新
Bus是SpringCloud的消息总线,可以借助消息队列(RabbitMQ)进行消息广播
1)安装RabbitMQ
Linux安装
① 安装erlang
wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
yum install epel-release
yum install erlang
② 安装rabbitmsq
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.9.7/rabbitmq-server-3.9.7-1.el7.noarch.rpm
yum install rabbitmq-server-3.9.7-1.el7.noarch.rpm # 目前的最新版本 支持erlang24
③ 启动rabbitmsq
service rabbitmq-server start
④ 启用管理工具
rabbitmq-plugins enable rabbitmq_management
⑤ 防火墙允许端口
firewall-cmd --permanent --add-port=15672/tcp
firewall-cmd --permanent --add-port=5672/tcp
⑥ 将配置文件模板复制到etc目录
cp /usr/share/doc/rabbitmq-server-3.9.7-1/rabbitmq.config.example /etc/rabbitmq/rabbitmq.config
⑦ 通过vi命令编辑
vi /etc/rabbitmq/rabbitmq.config
修改下面内容:
注意要去掉后面的逗号
⑧ 设置开机启动
chkconfig rabbitmq-server on
Windows安装
① 安装erlang和rabbitmq
②打开菜单输入命令,启动管理工具
rabbitmq-plugins enable rabbitmq_management
④ 启动rabbit
net start rabbitmq
net stop rabbitmq
⑤ 浏览器输入: http://localhost:15672 账号密码都是guest
2) Config服务和客户端都添加依赖(服务端需要actuator依赖)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
3)Config服务和客户端都添加配置
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
4)Config服务暴露端点
management.endpoints.web.exposure.include=*
5)Webhook向Config服务发送post请求
http://ywki8i.natappfree.cc/actuator/bus-refresh
注意: 需要将过滤器中的代码进行修改
url.endsWith("/actuator/bus-refresh"))