小编近期学习微服务配置中心了解到几个常用的配置中心组件,分别是SpringCloud Config,携程开源框架Apollo,以及阿里开源组件Nacos,出于学习需要并没有做非常深入的了解。SpringCloud Config是SpringCloud自带的配置中心,这里不做说明。Apollo则是携程开源的一个框架,这个框架总体还是不错的,但是小编认为Apollo的发布粒度是配置项级别,也就是说SpringCloud微服务只能从Apollo中获取一个个的配置项,实际上在使用时并不是很方便。因此有没有发布粒度是到文件级别的配置中心呢?答案是有的,这个配置中心就是阿里的Nacos,下面将简单介绍一下Nacos,并且我们的示例尽量贴近实际项目需求,我们的目标是将application.yml的文件配置放在Nacos配置中心,微服务启动时先加载bootstrap.properties文件,在bootstrap.properties中请求Nacos配置中心拉取对应的配置文件到微服务中,从而实现微服务的配置文件中心化管理。
首先,让我们先认识一下什么是Nacos?
对于Nacos的说明,可以查看阿里nacos官方文档手册 https://nacos.io/zh-cn/
为了方便阅读,这里还是简单介绍一下Nacos可以做什么(说明来自官方文档手册):
服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:
Kubernetes Service
gRPC & Dubbo RPC Service
Spring Cloud RESTful Service
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 (控制台) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
动态 DNS 服务
动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。
Nacos 提供了一些简单的 DNS APIs TODO 帮助您管理服务的关联域名和可用的 IP:PORT 列表.
服务及其元数据管理
Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
也就是说Nacos可以集中管理当前比较主流的服务,比如K8S,Dubbo,SpringCloud。
下面,让我们开始看下怎么使用,本文仅以windows下单机进行展示,而对于集群其实根据文档说明也只需要配置很少的配置文件,部署也是比较简单的感兴趣可以自行查阅文章了解。
为了贴近实际项目需要,我们这里直接采用Nacos集成Spring Cloud,步骤如下:
一.下载Nacos安装包并启动Nacos:文档可查阅官方文档说明https://nacos.io/zh-cn/docs/quick-start.html
下载安装包之前,需要以下基本的预备环境:
小编这里下载的是当前最新版Nacos-1.3.1.zip版,下载后直接解压,然后不需要改任何文件,在bin目录下找到startup.cmd文件,采用cmd startup.cmd -m standalone命令执行,或者直接双击执行即可。
启动好之后,在浏览器输入http://127.0.0.1:8848/nacos,即可弹出Nacos控制台页面,需要输入账号密码(使用Spring Security做的安全认证):nacos/nacos。
登录之后就可以添加配置了,下面将着重介绍下Nacos配置中心比较关键的一些概念。
其中本文只提及本文在bootstrap.properties中使用到的一些概念,以及这些概念是怎么使用的,完整Nacos包含的概念可以查看https://nacos.io/zh-cn/docs/concepts.html
这里贴出bootstrap.properties的配置:
#服务器地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
#应用名
spring.application.name=nacos
#默认为Public命名空间,可以省略不写
spring.cloud.nacos.config.namespace=Public
#指定配置群组 --如果是Public命名空间 则可以省略群组配置
spring.cloud.nacos.config.group=DEFAULT_GROUP
#prefix文件名 -- 如果没有配置则默认为 ${spring.application.name}
spring.cloud.nacos.config.prefix=my
#指定开发环境
spring.profiles.active=dev
#指定文件后缀
spring.cloud.nacos.config.file-extension=yaml
#最终拼接出来的就是:my-nacos-dev.yaml (一定要注意约定!)
#Data ID = ${spring.cloud.nacos.config.prefix}.${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
#Group = ${spring.cloud.nacos.config.group}
(1)服务地址:server-addr:用于指定Nacos配置中心的地址。本文为本地环境,默认8848端口:127.0.0.1:8848。
(2)命名空间Namespace:用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
这个配置可以将不同的配置文件隔离开来,可以在控制台中自定义添加,默认是Public,如果想使用自定义命名空间内的配置,则需要配置这个spring.cloud.nacos.config.namespace:
(3)配置分组Group:Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或 Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置和 MQ_topic 配置。
这个配置可以用于给统一命名空间内的配置进行分组,不同组的配置互不干扰,默认是DEFAULT_GROUP,也可以在新建配置时手动输入Group值进行新建自定义组。
(4)配置集ID(DataId):Nacos 中的某个配置集的 ID,配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。Data ID 通常采用类 Java 包(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。此命名规则非强制。
这个配置集Id则是用于区分同一个命名空间内同一个组不同配置的唯一ID,这个命名需要遵循指定的规范:
在 Nacos Spring Cloud 中,dataId
的完整格式如下:
${prefix}-${spring.profiles.active}.${file-extension}
prefix
默认为 spring.application.name
的值,也可以通过配置项 spring.cloud.nacos.config.prefix
来配置。spring.profiles.active
即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profiles.active
为空时,对应的连接符 -
也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
file-exetension
为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension
来配置。目前只支持 properties
和 yaml
类型。spring.cloud.nacos.config.prefix可以用于想要自定义指定加载文件名的时候配置,默认加载
spring.application.name。
spring.profiles.active可以用于指定加载哪个环境的配置文件,如dev或prod。
file-exetension可以用于指定文件的后缀名,如yml,yaml,properties等,如果想同时指定多种文件则用逗号隔开。
根据上面关于dataId的命名规则,例如如下配置就可以找到对应配置文件是 Test命名空间下MY_GROUP组的my-nacos-prod.yaml配置文件:
spring.application.name=nacos
spring.cloud.nacos.config.namespace=Test
spring.cloud.nacos.config.group=MY_GROUP
spring.cloud.nacos.config.prefix=my-nacos
spring.profiles.active=prod
spring.cloud.nacos.config.file-extension=yaml
介绍完本文使用到的概念之后,我们就能理解在Nacos配置中心创建的各个文件配置是什么含义了,如下例子:
下面重点介绍如何在SpringCloud服务启动时就自动去加载Nacos配置到Spring环境中:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.2.RELEASE
com-springcloud-nacos
com.springcloud.nacos
1.0-SNAPSHOT
1.8
Hoxton.SR8
org.springframework.cloud
spring-cloud-dependencies
${spring.cloud-version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.2.0.RELEASE
pom
import
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-config
0.2.1.RELEASE
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.2.0.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
com.alibaba.boot
nacos-config-spring-boot-starter
0.2.7
org.springframework.cloud
spring-cloud-context
2.2.2.RELEASE
com.alibaba.nacos
nacos-client
1.2.0
org.springframework.boot
spring-boot-maven-plugin
注意:版本 2.1.x.RELEASE 对应的是 Spring Boot 2.1.x 版本。版本 2.0.x.RELEASE 对应的是 Spring Boot 2.0.x 版本,版本 1.5.x.RELEASE 对应的是 Spring Boot 1.5.x 版本。
更多版本对应关系参考:版本说明 Wiki
https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明
这里主要需要注意SpringCloud,SpringBoot,SpringCloud Alibaba三个版本的对应,因为SpringCloud启动会优先加载bootstrap.properties,其次是bootstrap.yml,再才是SpringBoot中的application.yml文件,但是本文中将SpringBoot的application.yml放在了Nacos中,因此整个执行过程是SpringCloud启动时自动加载bootstrap.properties,在bootstrap.properties中配置Nacos获取指定配置文件,最后将获取到的配置文件内容交给SpringBoot装载到Spring容器当中。
那么问题来了,SpringCloud和SpringBoot到底是一个什么关系呢?为什么是这样一个加载过程呢?
原理就是SpringCloud是比SpringBoot更高一级的存在,因为假设SpringBoot优先加载,那么在获取Nacos配置之前整个容器所需要的的环境配置就已经初始化结束了,这样即使获取到Nacos的配置也没有用了。因此为了解决这个问题,正确的逻辑应该是SpringCloud设置为更高一级,在SpringCloud启动时会创建一个父容器执行bootstrap.properties对Nacos获取配置并进行包装,和SpringBoot中的Spring容器形成父子容器,父容器的执行顺序因此会更优先,获取到Nacos的配置后再提交给子容器(SpringBoot的Spring环境),进而将Nacos中的配置可以初始化到Spring环境中使用。
说完SpringCloud和SpringBoot加载顺序原理后,那么SpringCloud和SpringCloud Alibaba又是什么关系呢?
实际上SpringCloud Alibaba是对SpringCloud的扩展,SpringCloud Alibaba有很多拓展组件,Nacos就是其中一个,因此如果要使用Nacos就需要添加SpringCloud Alibaba的依赖,也自然需要适配不同版本的SpringCloud。更多关于SpringCloud Alibaba的组件可以查看Spring.io官网-SpringCloud-SpringCloud Alibaba章节https://spring.io/projects/spring-cloud-alibaba
本文推荐使用的组合是:
SpringCloud Hoxton.SR8(H版)+SpringBoot2.2.2.RELEASE+SpringCloudAlibaba2.2.0.RELEASE+Nacos1.3.1
下面我们就进行演示这个过程,为了简单示例我们仅在Nacos的配置文件中加入server.port=8022一个设置端口号的配置项。
(1)在 bootstrap.properties
中配置 Nacos server 的地址和应用名等nacos参数,指定获取nacos-dev.yaml文件配置
spring.application.name=nacos
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.bootstrap.enable=true
spring.cloud.nacos.config.bootstrap.log.enable=true
spring.profiles.active=dev
spring.cloud.nacos.config.namespace=public
spring.cloud.nacos.config.group=DEFAULT_GROUP
spring.cloud.nacos.config.file-extension=yaml
说明:之所以需要配置 spring.application.name
,是因为它是构成 Nacos 配置管理 dataId
字段的一部分。
(2)编写启动类代码:注意由于使用了SpringCloud2.2以上的版本,这里需要在@SpringBootApplication(scanBasePackages={"com.netflix.client.config","com.nacos"})中手动添加com.netflix.client.config的包扫描,否则启动时会报IClient不存在的错误,同时也将自己的根路径com.nacos加到包扫描中。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* springcloud超过2.2.x,则要加这个com.netflix.client.config,否则启动会报错
*/
@SpringBootApplication(scanBasePackages={"com.netflix.client.config","com.nacos"})
public class NacosConfigApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigApplication.class, args);
String port = applicationContext.getEnvironment().getProperty("serve.port");
System.err.println("port:"+port);
}
}
编写RestController代码:注意可以 使用Spring Cloud 原生注解 @RefreshScope
实现配置自动监控和更新。
package com.nacos;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/config")
@RefreshScope //对Bean进行动态刷新,添加 @RefreshScope 或 @ConfigurationProperties注解。
public class ConfigController {
@Value("${server.port}")
private String port;
/**
* 在nacos获取port是8022端口
* http://localhost:8022/config/getPort
*/
@RequestMapping("/getPort")
public String getPort() {
System.out.println("/config/getPort="+port);
return port;
}
}
访问 http://localhost:8080/config/getPort
,此时返回内容为对应Nacos更改前的配置值。
当去Nacos控制台修改port值时,重新访问则可以看到port值
被动态更新了,但是注意这个port虽然动态更新了但是由于还涉及Tomcat等配置,因此尽管这个port被动态更新了但是想要Tomcat能使用更新后的port端口,依旧需要重新启动服务。
至此,本文使用SpringCloud+SpringBoot+Nacos实现简单的启动加载Nacos配置并加载到项目中的小应用就完成了,更多关于Nacos集群,灰度发布等高级使用可以自行了解学习。
最后总结SpringCloud Config,Apollo和Nacos的优缺点和选型:
Spring Cloud Config 将应用名称和对应Git中的文件名称关联起来了,这样可以起到多个应用配置相互隔离的作用,与Git搭配使用在部署环境上比较麻烦,还是满足大多数项目的需要。
Apollo的配置都是在某个应用下面的(除了公共配置),也起到了多个应用配置相互隔离的作用,有本地的mysql数据库,需要关联mysql数据库执行创建mysql apollo脚本,所有控制台的数据操作都会持久化到mysql的表当中,但是粒度只能到配置项,不能以完整配置文件的方式配置。
Nacos的应用概念比较弱,只有一个用于区分配置的额外属性,不过可以使用 Group 来做应用字段,可以起到隔离作用,nacos单机模式使用的是本地数据库,可以配置SpringCloud,Dubbo,K8S等主流服务,配置可以做到文件级别的配置和发布,总体nacos性能较好。
由于小编了解并没有很深入,更多比较可以查看其他博主的文档介绍。本文就到这里了,做个记录方便后面实际应用时查阅。