Nacos配置管理
什么是配置中心
1.1 什么是配置
应用程序在启动和运行的时候往往需要读取一些配置信息,配置基本上伴随着应用程序的整个生命周期,比如:数据库连接参数、启动参数等。
配置主要有以下几个特点:
- 配置是独立于程序的只读变量:配置对于程序是只读的,程序通过读取配置来改变自己额行为,但是程序不应该去改变配置
- 配置伴随应用的整个生命周期:配置贯穿于应用整个生命周期,应用在启动时通过读取配置来初始化,在运行时根据配置调整行为,比如:启动时需要读取服务的端口号,系统在运行过程中需要读取定时策略执行定时任务等
- 配置可以有多种加载方式:常见的有程序内部
hard code
、配置文件、环境变量、启动参数、基于数据库库等。 - 配置需要治理:同一份程序在不同的环境、不同的集群经常需要有不同的配置,所以需要有完善的环境、集群配置策略。
1.2 什么是配置中心
在微服务架构中,当系统从一个单体应用,被拆分成分布式系统上的一个个节点后,配置文件也必须跟着迁移,这样配置就分散了,不仅如此,分散中还包含着冗余:
配置中心将配置从各个应用中剥离出来,对配置进行统一管理,应用自身不需要自己去管理配置。
配置中心的服务流程如上图
Nacos简介
2.1 主流配置中心对比
目前比较流行的配置中心有:Spring Cloud Config
、Apollo
、Nacos
、Disconf
(不在维护)等
对比项 | Spring Cloud Config | Apollo | Nacos |
---|---|---|---|
配置实时推送 | 支持(Spring Cloud Bus) | 支持 | 支持(Http长轮询1s) |
版本管理 | 支持(Git) | 支持 | 支持 |
配置回滚 | 支持(Git) | 支持 | 支持 |
灰度发布 | 支持 | 支持 | 支持 |
权限管理 | 支持(Git) | 支持 | 支持 |
多集群 | 支持 | 支持 | 支持 |
多环境 | 支持 | 支持 | 支持 |
监听查询 | 支持 | 支持 | 支持 |
多语言 | 仅支持JAVA | 主流语言,Open API | 主流语言,Open API |
配置格式校验 | 不支持 | 支持 | 支持 |
单机读(QPS) | 7 | 9000 | 15000 |
单机写(QPS) | 5 | 1100 | 1800 |
3节点读(QPS) | 21 | 27000 | 45000 |
3节点写(QPS) | 5 | 3300 | 5600 |
从上表可以得出,性能方面Nacos的读写性能最好;功能方面Apollo最完善,Nacos具有Apollo的大部分配置管理功能,而Spring Cloud Config依赖Git场景不适合开放的大规模自动化运维API。
2.2 Nacos简介
阿里的开源产品,针对微服务架构中额服务发现、配置管理、服务治理的综合型解决方案。
官方介绍:
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
2.3 Nacos特性
-
服务发现和服务健康监测
Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。
Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。
-
动态配置服务
动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
Nacos 提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
-
动态 DNS 服务
动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。
Nacos 提供了一些简单的 DNS APIs TODO 帮助您管理服务的关联域名和可用的 IP:PORT 列表.
-
服务及其元数据管理
Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
Nacos快速入门
3.1 安装Nacos Server
3.1.1预备环境准备
Nacos 依赖JAVA
环境来运行
- 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
- 64 bit JDK 1.8+;下载 & 配置。
- Maven 3.2.x+;下载 & 配置。
3.1.2 下载源码或者安装包
-
从Git上下载
git clone https://github.com/alibaba/nacos.git cd nacos/ mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U ls -al distribution/target/ cd distribution/target/nacos-server-$version/nacos/bin
-
下载编译后压缩包
您可以从 最新稳定版本 下载
nacos-server-$version.zip
包。unzip nacos-server-$version.zip #或者 tar -xvf nacos-server-$version.tar.gz cd nacos/bin
3.1.3 启动服务器
-
Linux/Unix/Mac
#启动命令(standalone代表着单机模式运行,非集群模式): sh startup.sh -m standalone #如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行: bash startup.sh -m standalone
-
Windows
#启动命令(standalone代表着单机模式运行,非集群模式): startup.cmd -m standalone
访问:http://192.168.145.1:8848/nacos/index.html
输入用户名/密码:nacos/nacos
3.1.4 OPEN API配置管理测试
-
服务注册
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
-
服务发现
curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
-
发布配置
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"
3.1.5 关闭服务器
3.1.6 外部mysql数据库支持
-
安装MySQL
-
创建数据库nacos,导入初始文件
nacos\conf\nacos-mysql.sql
-
修改配置,改为本地数据库配置
spring: datasource: platform: mysql db: num: 1 url: jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC user: nacos password: nacos
3.2 Nacos配置入门
3.2.1 发布配置
3.2.2 Nacos客户端获取配置
-
JAVA
-
引入依赖
<dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>2.0.1</version> </dependency>
-
编码实现
//定义Nacos Server地址 String serverAddr = "127.0.0.1"; //定义DataId String DataId = "test"; //定义分组 String Group = "DEFAULT_GROUP"; Properties properties = new Properties(); properties.put(PropertyKeyConst.SERVER_ADDR,serverAddr); ConfigService configService = NacosFactory.createConfigService(properties); String content = configService.getConfig(DataId, Group,5000); System.out.println(content); //监听配置服务 configService.addListener(DataId, Group, new Listener() { @Override public Executor getExecutor() { return null; } @Override public void receiveConfigInfo(String content) { System.out.println("接收到内容:" + content); } }); //测试发布配置 boolean isPublish = configService.publishConfig(DataId, Group, "content"); System.out.println("发布配置:" + isPublish); Thread.sleep(3000); //获取配置 String config = configService.getConfig(DataId, Group,5000); System.out.println("获取配置:" + config); Thread.sleep(3000); //删除配置 boolean isRemove = configService.removeConfig(DataId, Group); System.out.println("删除配置:" + isRemove); Thread.sleep(3000); //获取配置 String config2 = configService.getConfig(DataId, Group,5000); System.out.println("获取配置:" + config2);
-
-
Spring Boot
-
引入依赖
<!-- nacos 依赖 --> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>nacos-config-spring-boot-starter</artifactId> <version>${nacos-config-spring-boot.version}</version> </dependency>
-
启动类配置
@NacosPropertySource(dataId = "example", autoRefreshed = true)
-
配置文件
nacos.config.server-addr=127.0.0.1:8848
-
代码实现
@Controller @RequestMapping("/config") public class NacosTest2 { @NacosValue(value = "${useLocalCache:false}" ,autoRefreshed = true) private boolean useLocalCache; @RequestMapping("/get") public boolean getConfig(){ return useLocalCache; } }
-
-
Spring Cloud
-
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>0.2.1.RELEASE</version> </dependency>
-
配置文件
spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.application.name=example
-
代码实现
@RestController @RequestMapping("/config") @RefreshScope public class ConfigController { @Value("${useLocalCache:false}") private boolean useLocalCache; @RequestMapping("/get") public boolean get() { return useLocalCache; } }
-
Nacos配置管理基础应用
4.1 Nacos配置管理模型
对于Nacos配置管理,通过Namespace、group、Data Id能够定位到一个配置集。
-
配置集(Data Id)
在系统中,一个配置文件通常就是一个配置集,一个配置集可以包含系统的各种配置信息,例如数据源、线程池、日志级别等,每个配置集都可以定义一个有意义的名称,就是配置集的ID(Data Id)
-
配置项
配置集中包含的一个个配置内容就是配置项,它代表一个具体的可配置的参数与其值域,通常以
key=value
的形式存在。 -
配置分组(Group)
配置分组是对配置集进行分组,通过一个有意义的字符串来表示,不同的配置分组可以有相同的配置集(Data Id)。
-
命名空间(Namespace)
命名空间可用于进行不同环境的配置隔离,例如可以隔离开发环境、测试环境、生产环境,因为它们的配置可能不相同,或者是隔离不同的用户,不同的开发人员使用同一个nacos管理各自的配置,可通过Namespace隔离,不同的命名空间下,可以存在相同名称的配置分组(Group)或配置集(Data Id)。
-
最佳实践分配
- 命名空间(Namespace):环境,例如测试、开发、部署
- 配置分组(Group):项目,不同的项目使用不同的Group
- 配置集(Data Id):工程,项目下存在多个工程,每个配置集是一个工程的配置文件
4.2 命名空间管理
4.2.1 命名空间隔离设计
Namespace的设计是nacos基于此做多环境及多租户(多个用户共同使用Nacos)数据(配置和服务)隔离的。
- 从一个租户来说,如果存在多套不同的环境,那么这个时候可以根据指定的环境来创建不同的Namespace,以此来实现多环境的隔离。
- 从多租户来说,每个租户可能存在自己的Namespace,每个租户的配置数据及注册的服务数据都会归属到自己的Namespace下,以此来实现多租户的数据隔离。
Nacos配置管理应用于分布式系统
5.1 分布式应用配置管理
- 用户通过Nacos Server的控制台集中对多个服务的配置进行管理。
- 各服务统一从Nacos Server获取各自的配置,并监听配置的变化
5.1.1 发布配置
我们规划两个服务Server1
、Server2
,并且通过Nacos发布配置,对这两个服务的配置进行集中维护。
Server1
配置如下:
Namespace: 1111111111111111 #开发环境
Data Id:server1.yml
配置格式: YAML
配置内容:
common:
name: server1 config
Server2
配置如下:
Namespace: 2222222222222222 #开发环境
Data Id:server2.yml
配置格式: YAML
配置内容:
common:
name: server2 config
5.1.2 创建父工程
-
创建父工程
nacos_demo
-
配置
pom
文件<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <modules> <module>nacos-server1</module> <module>nacos-server2</module> </modules> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.4.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <finalName>nacos_demo</finalName> <pluginManagement> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> </plugins> </pluginManagement> </build>
5.1.3 微服务service1
配置
-
创建子服务
server1
-
引入依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies>
-
编写配置文件
server: port: 8080 spring: application: name: server1 cloud: nacos: config: namespace: 111 group: Test server-addr: 127.0.0.1:8848 file-extension: yaml
-
配置启动类及测试代码
@SpringBootApplication @RestController public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class,args); } @Value("${common.name}") private String config1; @RequestMapping(value = "/get",method = RequestMethod.GET) public String getConfig(){ return config1; } }
5.1.4 微服务service2
配置
-
创建子服务
server2
-
引入依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies>
-
编写配置文件
server: port: 8080 spring: application: name: server2 cloud: nacos: config: namespace: 22222 group: Test server-addr: 127.0.0.1:8848 file-extension: yaml
-
配置启动类及测试代码
@SpringBootApplication @RestController public class Server2Application { public static void main(String[] args) { SpringApplication.run(Server2Application.class,args); } @Value("${common.name}") private String config1; @RequestMapping(value = "/get2",method = RequestMethod.GET) public String getConfig(){ return config1; } }
5.1.5 支持配置的动态更新
@Autowired
private ConfigurableApplicationContext applicationContext; //声明上下文对象
@RequestMapping(value = "/get",method = RequestMethod.GET)
public String getConfig(){
return applicationContext
.getEnvironment()
.getProperty("common.name"); //获取实时参数值
}
5.1.7 自定义扩展的Data Id配置
spring:
application:
name: server1
cloud:
nacos:
config:
namespace: 111
group: Test
server-addr: 127.0.0.1:8848
file-extension: yaml
ext-config[0]: #配置扩展
#配置在默认DEFAULT_Group,不支持动态刷新
data-id: extserver1.yml
ext-config[1]:
#配置在默认DEFAULT_Group,不支持动态刷新
data-id: extserver2.yml
group: Test_Group
ext-config[2]:
#配置在默认DEFAULT_Group,支持动态刷新
data-id: extserver2.yml
group: Test_Group
refresh: true
5.1.8 自定义共享Data Id配置
spring:
application:
name: server1
cloud:
nacos:
config:
namespace: 111
group: Test
server-addr: 127.0.0.1:8848
file-extension: yaml
#配置共享DATA ID,仅支持DEFAULT_Group的加载,其他组不加载
shared-dataids: extserver1.yml,extserver2.yml,extserver3.yml
refreshable-dataids: extserver3.yml
5.1.9 配置的优先级
Nacos目前提供三类拉取配置的方式
- A:通过
spring.cloud.nacos.config.shared-dataids
支持多个共享Data Id的配置 - B:通过
spring.cloud.nacos.config.ext-config[n].data-id
的方式配置多个配置 - C:内部相关规则(应用名+扩展名)自动生成的data id配置
三种方式的优先级为:C > B > A
5.1.10 完全关闭配置
spring:
application:
name: server1
cloud:
nacos:
config:
#完全关闭nacos配置
enabled: false
5.2 Nacos集群部署
5.2.1 集群部署
3各或3各以上Nacos节点才能构成集群
-
安装3个以上Nacos
复制
Nacos
3份,分别命名为Nacos
1、Nacos
2、Nacos
3,修改nacos/conf
目录下application.properties
中的server.port
为8848、8849、8850 -
配置集群配置文件
在所有
nacos
目录的conf
目录下,有文件cluster.conf.example
,将其命名为cluster.conf
,并将每行配置成ip:port
# ip:port 127.0.0.1:8848 127.0.0.1:8849 127.0.0.1:8850
5.2.2 客户端配置
spring:
application:
name: server1
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850