Nacos(配置中心)实践

一、安装Nacos Server

安装之前请确保Java环境和maven环境正常:

  • 64 bit JDK 1.8+;
  •  Maven 3.2.x+

1、下载源码或者安装包

我选择直接下载安装包:https://github.com/alibaba/nacos/releases下的nacos-server-1.1.3.zip

2、启动服务

双击startup.cmd运行文件

出现以下界面说明运行成功了

如果启动失败有可能是外部数据库没配置好,执行一下下面的sql就行:

可以看到已经创建了nacos所需的数据库:

启动成功,可通过浏览器访问 http://127.0.0.1:8848/nacos ,打开如下 nacos 控制台登录页面:
账号密码都默认是nacos,登录即可打开nacos的管理主页面

3、OPEN API配置管理测试

启动nacos成功后,可通过nacos提供的http api验证nacos服务运行是否正常。我使用的是Postman测试

3.1、发布配置

如下Post命令表示向nacos发布一个配置:

可以看到返回为true,在nacos的管理控制台也可以看到刚才添加的配置:
配置详情如下:

3.2、获取配置

nacos 发布配置成功,就可以通过客户端从 nacos 获取配置信息,执行下边的命令:
GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=test_id &group=test_group "

通过测试发现,可以从nacos获取前边发布的配置:HelloWorld 

到此说明安装成功了。

3.3、关闭服务器

双击 shutdown.cmd 运行文件

3.4、外部mysql数据库支持

单机模式时 nacos 默认使用嵌入式数据库实现数据的存储,若想使用外部 mysql 存储 nacos 数据,需要进行额外配置。不赘述了。

二、配置入门基础

1、发布配置

除了使用open api外,一般都是在nacos控制台直接配置。浏览器访问http://127.0.0.1:8848/nacos,打开nacos控制台,并点击菜单配置管理->配置列表

Nacos 添加如下的配置:
Data ID: hello-nacos.yaml
Group : DEFAULT_GROUP
配置格式 : YAML
配置内容: someconfig :
                          config1: something

第一步:点击新增配置

第二步:配置信息
第三步:发布配置
在第二步点击 发布 ,如下图,点击确定发布成功。
这时候可以在控制台看到刚才添加的配置

2、nacos客户端获取配置

(1)新建一个名为nacos-demo的项目,使用的依赖如下:

<dependency>
      <groupId>com.alibaba.nacos</groupId>
      <artifactId>nacos-client</artifactId>
      <version>1.1.3</version>
</dependency>

 (2)编写Java类获取外部化配置

通过ConfigService这个类获取,完整代码如下:

public class SimpleDemoMain {
    public static void main(String[] args) throws NacosException {
        String serverAddr = "127.0.0.1:8848";   //nacos地址
        String dataId = "hello-nacos.yaml";
        String group = "DEFAULT_GROUP";

        Properties properties = new Properties();
        properties.put("serverAddr",serverAddr);
        ConfigService configService = NacosFactory.createConfigService(properties);
        //获取配置,String dataId, String group, long timeoutMs
        String content = configService.getConfig(dataId, group, 5000);
        System.out.println(content);
    }
}
启动 SimpleDemoMain ,控制台得到以下内容说明成功:

3、Nacos配置相关概念

对于 Nacos 配置管理,通过 Namespace group Data ID 能够定位到一个配置集。
配置集 (Data ID)
在系统中,一个配置文件通常就是一个 配置集 ,一个配置集可以包含了系统的各种配置信息,例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。每个配置集都可以定义一个有意义的名称,就是配置集的ID DataID。
配置分组 (Group)
配置分组是对配置集进行分组,通过一个有意义的字符串(如 Buy Trade )来表示,不同的配置分组下可以有相同的配置集(Data ID )。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:可用于区分不同的项目或应用,例如:学生管理系统的配置集可以定义一个group 为: STUDENT_GROUP
命名空间 (Namespace)
命名空间( namespace )可用于进行不同环境的配置隔离。例如可以隔离开发环境、测试环境和生产环境,因为它们的配置可能各不相同,或者是隔离不同的用户,不同的开发人员使用同一个nacos 管理各自的配置,可通过namespace隔离。不同的命名空间下,可以存在相同名称的配置分组 (Group) 或 配置集。
概括来说:
Namespace :代表不同 环境 ,如开发、测试、生产环境。
Group :代表某 项目 ,如 XX 医疗项目、 XX 电商项目
DataId :每个项目下往往有若干个 工程 ,每个配置集 (DataId) 是一个工程的 主配置文件
获取某配置集的代码
获取配置集需要指定:
1 nacos 服务地址,必须指定
2 namespace ,如不指定默认 public
3 group ,如不指定默认 DEFAULT_GROUP
4 dataId ,必须指定

4、配置管理

Nacos 支持基于 Namespace Group的配置分组管理,以便用户更灵活的根据自己的需要按照环境或者应用、模块等分组管理微服务的大量配置,在配置管理中主要提供了配置历史版本、回滚、订阅者查询、导出导入、克隆等核心管理能力。这些功能都可以在控制台直接操作,着重记录一下监听查询。

4.1、 监听查询

Nacos 提供配置订阅者即监听者查询能力,同时提供客户端当前配置的 MD5 校验值,以便帮助用户更好的检查配置变更是否推送到 Client 端。通过以下代码可对某配置进行监听:
public class SimpleDemoMainListener {
    public static void main(String[] args) throws NacosException {
        //nacos 地址
        String serverAddr = "127.0.0.1:8848";
        String dataId = "hello-nacos.yaml";
        String group = "DEFAULT_GROUP";
        Properties properties = new Properties();
        properties.put("serverAddr",serverAddr);
        ConfigService configService = NacosFactory.createConfigService(properties);
        String content = configService.getConfig(dataId, group, 5000);
        System.out.println(content);

        //添加监听String dataId, String group, Listener listener
        configService.addListener(dataId, group, new Listener() {
            public Executor getExecutor() {
                return null;
            }
            public void receiveConfigInfo(String s) {
                //当配置发生变化时的响应
                System.out.println(s);
             }
        });

        // 测试让主线程不退出,因为订阅配置是守护线程,主线程退出守护线程就会退出。正式代码中无需下面代码
        while (true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

当我们点击运行时和上面的获取配置效果是一样的,Java控制台输出:

然后我们在Nacos将hello-nacos.yaml修改(something修改为anything),此时可以看到Java控制台成功监听到我们的修改动作并且获取了最新的配置:

三、分布式应用配置管理

下图展示了如何通过 Nacos 集中管理多个服务的配置:
  • 用户通过Nacos Server的控制台集中对多个服务的配置进行管理。
  • 各服务统一从Nacos Server中获取各自的配置,并监听配置的变化。

1、发布配置

为了便于管理,新建一个命名空间dev和两个配置service1和service2:
service1
Namespace:9cd826a1-2bb5-4eeb-a2fb-20cb95ea65f2 #开发环境
Data ID: service1.yaml
Group : TEST_GROUP
配置格式 : YAML
配置内容: common:
                         name: service1 config

service2:

 Namespace:9cd826a1-2bb5-4eeb-a2fb-20cb95ea65f2#开发环境

Data ID: service2.yaml
Group : TEST_GROUP
配置格式 : YAML
配置内容: common:
                         name: service2 config

2、创建工程

2.1、创建父工程

父工程的完整pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xxx</groupId>
    <artifactId>nacos-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>service1</module>
        <module>quickstart</module>
    </modules>

    <packaging>pom</packaging>


    <dependencies>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.1.3</version>
        </dependency>
    </dependencies>

    <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.3.RELEASE</version> <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring‐boot‐maven‐plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.2、新建项目service1和service2

添加依赖:
<parent>
        <artifactId>nacos-demo</artifactId>
        <groupId>com.xxx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service1</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
bootstrap.yml 配置:
一般来说, spring boot 的配置将在 application.yml( 也可以是 application.properties) 文件中编写, 由于使用外部配置中心, 必须将原先的application.yml重命名为bootstrap.yml,否则无法连接配置中心 bootstrap.yml如下所示,以下配置文件说明该应用将从地址为 127.0.0.1:8848 配置中心获取配置,通过配置信息定位配置集:
server:
  port: 56010

spring:
  cloud:
    nacos:
      config:
        group: TEST_GROUP
        server-addr: 127.0.0.1:8848
        file‐extension: yaml
        namespace: 9cd826a1-2bb5-4eeb-a2fb-20cb95ea65f2
  application:
    name: service1
dataId: 默认是服务名+扩展名(service1.yml)
启动配置客户端:
新增 Spring Boot 启动类,并增加获取配置的 web 访问端点 /confifigs ,通过标准的 spring @Value 方式,为了方便将测试的Controller写在了启动类里面
@SpringBootApplication
@RestController
public class Service1Bootstrap {
    public static void main(String[] args) {
        SpringApplication.run(Service1Bootstrap.class, args);
    }

    @Value("${common.name}")
    private String config1;

    @GetMapping("service1/config")
    public String getConfig1(){
        return config1;
    }
}

启动service1通过浏览器查看(之前写成了service1 comfig):

service2和service1配置流程一致,配置如下:
server:
  port: 56011

spring:
  cloud:
    nacos:
      config:
        group: TEST_GROUP
        server-addr: 127.0.0.1:8848
        file‐extension: yaml
        namespace: 9cd826a1-2bb5-4eeb-a2fb-20cb95ea65f2
  application:
    name: service2

编写启动类和service1类似,通过浏览器访问:

这种方式在服务启动时一次性获取配置,当我们在nacos更改配置,是不能获取最新的值的,除非重启项目, spring-cloud-starter-alibaba-nacos-confifig 支持配置的动态更新

2.3、支持配置的动态更新

基于2.2的例子,若要实现配置的动态更新,只需要进行如下改造(注入配置文件上下文):

@SpringBootApplication
@RestController
public class Service2Bootstrap {
    public static void main(String[] args) {
        SpringApplication.run(Service2Bootstrap.class, args);
    }

//    @Value("${common.name}")
//    private String config1;
//
//    @GetMapping("service2/config")
//    public String getConfig1(){
//        return config1;
//    }

    // 注入配置文件上下文
    @Autowired
    private ConfigurableApplicationContext applicationContext;

    @GetMapping("service2/config2")
    public String getConfig2(){
        return applicationContext.getEnvironment().getProperty("common.name");
    }
}

Note可以通过配置spring.cloud.nacos.confifig.refresh.enabled=false来关闭动态刷新

2.4、自定义扩展的DataId配置

通过自定义扩展的Data Id配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件。

新建一个service3子工程,配置文件如下:

server:
  port: 56012

spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: 9cd826a1-2bb5-4eeb-a2fb-20cb95ea65f2
        # 1、Data Id 在默认的组 DEFAULT_GROUP,不支持配置的动态刷新
        ext-config[0]:
          data-id: ext-config-common01.properties

        # 2、Data Id 不在默认的组,不支持动态刷新
        ext-config[1]:
          data-id: ext-config-common02.properties
          group: GLOBALE_GROUP

        # 3、Data Id 既不在默认的组,也支持动态刷新
        ext-config[3]:
          data-id: ext-config-common03.properties
          group: REFRESH_GROUP
          refresh: true
  application:
    name: service3

上面的配置文件遵循:

  • 通过spring.cloud.nacos.config.ext-config[n].data-id的配置方式来支持多个Data Id的配置。
  • 通过spring.cloud.nacos.config.ext-config[n].group的配置方式自定义Data Id所在的组,不明确配置的话,默认是 DEFAULT_GROUP
  • 通过spring.cloud.nacos.config.ext-config[n].refresh的配置方式来控制该Data Id在配置变更时,是否支持应用中可动态刷新, 感知到最新的配置值。默认是不支持的。
Note spring.cloud.nacos.config.ext - config[n].data - id 的值必须带文件扩展名,文件扩展名既可支持properties,又可以支持 yaml/yml
此时 spring.cloud.nacos.config.file - extension 的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。

上面用到的三个配置文件内容分别如下:

编写测试代码:

@SpringBootApplication
@RestController
public class Service3Bootstrap {
    public static void main(String[] args) {
        SpringApplication.run(Service3Bootstrap.class, args);
    }

    // 注入配置文件上下文
    @Autowired
    private ConfigurableApplicationContext applicationContext;

    @GetMapping("service3/config3")
    public String getConfig2(){
        String name = applicationContext.getEnvironment().getProperty("common.name");
        String age = applicationContext.getEnvironment().getProperty("common.age");
        String adderess = applicationContext.getEnvironment().getProperty("common.address");

        return name + "  " + age + " " + adderess;
    }
}

访问结果表明可以读到三个不同的配置文件内容:

2.5、自定义共享Data Id配置

为了更加清晰的在多个应用间配置共享的 Data Id ,你可以通过以下的方式来配置:
spring:
  cloud:
    nacos:
      config:
        shared‐dataids: ext-config-common01.properties,ext-config-common02.properties
        refreshable‐dataids: ext-config-common01.properties
可以看到:
  • 通过spring.cloud.nacos.config.shared-dataids来支持多个共享Data Id的配置,多个之间用逗号隔开。
  • 通过spring.cloud.nacos.config.refreshable-dataids来支持哪些共享配置的Data Id在配置变化时,应用中是否可动态刷新, 感知到最新的配置值,多个 Data Id之间用逗号隔开。如果没有明确配置,默认情况下所有共享配置的 Data Id都不支持动态刷新。

2.6、配置的优先级

Spring Cloud Alibaba Nacos Confifig 目前提供了三种配置能力从 Nacos 拉取相关的配置:
  • A:通过spring.cloud.nacos.config.shared-dataids支持多个共享DataId 的配置,按照配置出现的先后顺序,即后面的优先级要高于前面。
  • B:通过spring.cloud.nacos.config.ext-config[n].data-id的方式支持多个扩展DataId的配置,多个DataId 同时配置时,他的优先级关系是spring.cloud.nacos.config.ext-config[n].data-id其中n的值越大,优先级越高。
  • C:通过内部相关规则(应用名、扩展名)自动生成相关的Data Id配置
当三种方式共同使用时,他们的一个优先级关系是 :C > B >A,即默认>共享>扩展

2.7、完全关闭配置

通过设置spring.cloud.nacos.confifig.enabled = false来完全关闭Spring Cloud Nacos Confifig
 

四、Nacos集群部署

1、集群部署

3 个或 3 个以上 Nacos 节点才能构成集群
(1)安装3个以上Nacos
复制之前已经解压好的 nacos 文件夹,分别命名为 nacos nacos1 nacos2
2 )配置集群配置文件
在所有 nacos 目录的 conf 目录下,有文件 cluster.conf.example ,将其命名为 cluster.conf ,并将每行配置成ip:port。(请配置 3 个或 3 个以上节点)
由于是单机演示,需要更改 nacos/ conf 目录下 application.properties server.port ,防止端口冲突。如果服务器有多个ip 也要指定具体的 ip 地址,如: nacos.inetutils.ip-address=127.0.0.1 例如:
3)集群模式启动
分别执行 nacos 目录的 bin 目录下的startup
startup ‐m cluster
在任意一个 nacos 的控制台中,可以看到如下内容,此时8818为主节点:

2、客户端配置

所有客户端,分别指定 nacos 集群中的若干节点:
测试:
  • 关掉127.0.0.1:8848 nacos Leader实例,发现Leader被成功选举至127.0.0.1:8850
  • 紧接着重新启动 Provider ,这时马上请求 consumer /service 出现错误,发现 consumer provider 通信已经出现问题。但经过短暂的时间后,通信恢复。 通过测试,我们可以看到,通过以上的集群部署已经达到了高可用的效果。

3、生产环境部署建议

下图是官方推荐的集群方案,通过域名 + VIP 模式的方式来实现。客户端配置的 nacos ,当 Nacos 集群迁移时,客户端配置无需修改。
至于数据库,生产环境下建议至少主备模式。通过修改 ${nacoshome}/conf/application.properties 文件,能够使nacos拥有多个数据源。