配置中心简介
我们知道,除了代码之外,软件还有一些配置信息,比如数据库的用户名和密码,还有一些我们不想写死在代码里的东西,例如像线程池大小、队列长度等运行参数,以及日志级别、算法策略等, 还有一些是软件运行环境的参数,如Java 的内存大小,应用启动的参数,包括操作系统的一些 参数配置…… 所有这些东西,我们都叫做软件配置。以前,我们把软件配置写在一个配置文件中,就像 Windows 下的 ini 文件,或是 Linux 下的 conf 文件。然而,在分布式系统下,这样的方式就变得非常不好管理,并容易出错。假如生产环境下,项目现在正在运行,此时修改了配置文件,我们需要让这些配置生效,通常的做法是不是要重启服务。但重启是不是会带来系统服务短时间的暂停,从而影响用户体验呢,还有可能会带来经济上的很大损失(例如双11重启下服务)。基于这样的背景,配置中心诞生了。
动态修改服务的配置,实现服务的动态发布,实现服务器的不暂停更新
配置中心概述
配置中心最基础的功能就是存储一个键值对,用户发布一个配置(configKey),然后客户端获取这个配置项(configValue);进阶的功能就是当某个配置项发生变更时,不停机就可以动态刷新服务内部的配置项,例如,在生产环境上我们可能把我们的日志级别调整为 error 级别,但是,在系统出问题我们希望对它 debug 的时候,我们需要动态的调整系统的行为的能力,把日志级别调整为 debug 级别。还有,当你设计一个电商系统时,设计大促预案一定会考虑,同时涌进来超过一亿人并发访问的时候,假如系统是扛不住的,你会怎么办,在这个过程中我们一般会采用限流,降级。系统的限流和降级本质上来讲就是从日常的运行态切换到大促态的一个行为的动态调整,这个本身天然就是配置起到作用的一个相应的场景。
可以不停机更新服务的配置项
配置中心的选型
在面向分布式的微服务系统中,如何通过更高效的配置管理方式,实现微服务系统架构持续“无痛”的演进,并动态调整和控制系统的运行时态,配置中心的选型和设计起着举足轻重的作用。市场上主流配置中心有Apollo(携程开源),nacos(阿里开源),Spring Cloud Config(Spring Cloud 全家桶成员)。我们在对这些配置中心进行选型时重点要从产品功能、使用体验、实施过程和性能等方面进行综合考量。本次课程我们选择nacos,此组件不仅提供了注册中心,还具备配置中心的功能。
第一步:
编程未动,jar包先行:
<!--nacos配置中心依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
修改配置文件
将项目中的application.yml的名字修改为bootstrap.yml配置文件(启动优先级最高),代码如下:
spring:
application:
name: sca-provider #服务
cloud:
nacos: #每5s向nacos server发送一次信息,标记该服务还存在
discovery: #服务的注册和发现
server-addr: localhost:8848 #nacos server注册中心
config: #服务配置(可能经常变化的数据会写道配置中心种)
server-addr: localhost:8848 #配置中心
file-extension: yml #配置中心指定的配置格式扩展名
Nacos基本配置
打开nacos配置中心,新建配置,如图所示:
其中Data ID的值要与bootstrap.yml中定义的spring.application.name的值相同(服务名-假如有多个服务一般会创建多个配置实例,不同服务对应不同的配置实例)。
Controller处理器操作
在ProviderController中添加一个获取日志级别(debug<info<warn<error)的方法,代码如下:
@Slf4j
@RefreshScope
@RestController
public class ProviderController {
public ProviderController() {
System.out.println("ProviderController()");
}
//此属性会在对象构建时初始化
//服务器启动时会将所有配置信息(配置文件或配置中心)读取到Environment对象
//@Value用于告诉spring从Environment对象中读取配置信息
//将读取到配置内容赋值给对象的属性
@Value("${logging.level.com.cy}")
private String logLevel;
@GetMapping("/provider/doGetLogLevel")
public String doGetLogLevel() {
log.trace("==log.trace==");//跟踪
log.debug("==log.debug==");//调试
log.info("==log.info==");//常规信息
log.warn("==log.warn==");//警告
log.error("==log.error==");//错误信息
return "log level is " + logLevel;
}
}
其中,@RefreshScope的作用是在配置中心的相关配置发生变化以后,能够及时看到类中属性值的更新(底层是通过重新创建Controller对象的方式,对属性进行了重新初始化),Controller编写好以后,启动配置中心服务,然后进行访问测试。,打开浏览器直接在地址栏输入http://localhost:8081/provider/doGetLogLevel,检测输出结果是否为我们配置中配置的信息,如图所示。
配置中心是如何修改网页上显示数据的?
配置中心中修改数据。配置中心找到他维护的客户端,通知客户端获取新的数据,客户端获取数据之后会在本地更新储存,并在下次访问时刷新@Value注解描述的属性值,但是需要借助@RefreshScope注解对属性所在的类进行描述
通过分组区分配置信息
创建一个新的分组
选择id为b342c49c-5d5a-457b-95e3-7acf08bfb0ab分组为 DEFAULT_GROUP_5的1配置文件
spring:
application:
name: sca-provider #服务名
cloud:
nacos: #服务启动时会向nacos发送心跳包(5秒一次)
discovery: #服务的注册和发现
server-addr: localhost:8848 #nacos server
config: #服务配置(将可能经常变化的数据写到配置中心)
server-addr: localhost:8848
file-extension: yml #配置中心指定的配置信息格式的扩展名
namespace: b342c49c-5d5a-457b-95e3-7acf08bfb0ab
group: DEFAULT_GROUP_51
#选择id为b342c49c-5d5a-457b-95e3-7acf08bfb0ab分组为 DEFAULT_GROUP_5的1配置文件
如果查找不到对应的分组,那么会选取相同名字的配置
共享配置设计及读取
当同一个namespace的多个配置文件中都有相同配置时,可以对这些配置进行提取,然后存储到nacos配置中心的一个或多个指定配置文件,哪个微服务需要,就在服务的配置中设置读取即可。例如:
第一步:在nacos中创建一个共享配置文件,例如:
第二步:
在指定的微服务配置文件(bootstrap.yml)中设置对共享配置文件的读取,例如:
见红色区域内容。
spring:
application:
name: nacos-config
cloud:
nacos:
config:
# 共享配置
shared-configs[0]:
data-id: app-public-dev.yml
group: DEFAULT_GROUP
refresh: true #默认false
总结
一个配置文件可以有多个Namespace,
一个namespace可以有多个Group
一个Group可以有多个DataID