2.nacos服务配置中心

286 阅读12分钟

下面将研究以下几个问题:

  1. nacos的角色: nacos是如何工作的? 在集群中扮演什么样的角色?
  2. 修改nacos配置数据库: 我们在控制台配置的信息, 默认是写到nacos的默认数据库中, 不方便管理, 因此我们设置一个自己的数据库, 进行管理操作
  3. 在控制台配置nacos配置
  4. nacos配置管理的模型: 基本概念,namespace, group, data id及其用法
  5. 命名空间的管理, namespace的使用
  6. Nacos配置管理应用于分布式系统
  7. 7.Nacos集群部署

一. nacos的角色在这里插入图片描述

这张图说明了nacos是一个单独的服务器, 用户修改或者发布配置信息, 会通知下游的服务器. 下游的服务器也可以根据一定的规则读取配置中心的配置信息.

让nacos成为spring cloud集群的一部分

  1. 启动nacos服务

  2. 将nacos纳为spring cloud微服务的一部分

  3. 将spring cloud其他应用服务注册到nacos上.

二. 修改nacos配置数据库

下面验证服务的可用性

1. 启动nacos

./startup.sh -m standalone

注意: 这里一定要单机模式启动, 默认是集群模式, 我们现在没有在集群中, 会报异常.

2 往配置中心发布配置

nacos是一个服务, 他对外也提供了很多接口, 其中一个是添加配置的接口. 我们模拟这个接口进行配置:

curl -X POST "http://localhost:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"

看到返回结果是true. 然后刷新控制台, 可以看到如下 在这里插入图片描述

3. 从配置中心获取配置

curl -X GET "http://localhost:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test" 这个命令就是获取配置

在这里插入图片描述 获取helloworld内容

4. 改变nacos配置数据的存储位置

我们把配置信息添加到nacos, 那么,他是如何保存的呢? nacos某一个默认的自带数据库, 这个数据库不方便操作和查找. 因此我们将其替换为自己的mysql数据库

1. 准备一个mysql数据库

  因为mysql比较大, 所以,我使用的是docker安装的mysql

  下载mysql

  docker pull mysql:5.7.15

  启动mysql

docker run -p 3306:3306 --name MySQLDocker -v PWD/conf/my.cnf:/etc/mysql/conf.d/my.cnfvPWD/conf/my.cnf:/etc/mysql/conf.d/my.cnf -v PWD/logs:/var/log/mysql -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.15

2. 创建一个nacos_config的数据库 在这里插入图片描述

3. 初始化nacos_config表结构

在这里找到配置文件: ${nacosHome}/conf/nacos-mysql.

4. 修改application.properties配置文件 在这里插入图片描述 然后重新启动.

在执行上面的写配置

数据库里生成了一条配置信息: 在这里插入图片描述

三. nacos配置

1. 在控制台添加配置

Data ID: nacos-simple-demo.yaml
Group: DEFAULT_GROUP
配置格式: YAML
配置内容: 
common
  config: something

将以上信息在控制台配置好了 在这里插入图片描述 以上就是在nacos服务端建好了配置信息

2. 模拟nacos客户端--获取nacos服务端配置

public class DemoTest {

    public static void main(String[] args) throws NacosException {
        String dataId = "test.demo.yml";
        String group = "DEFAULT_GROUP";
        String serverAddr = "localhost:8848";

        Properties properties = new Properties();
        properties.setProperty("serverAddr", serverAddr);
        // 和nacos服务建立连接
        ConfigService configService = NacosFactory.createConfigService(properties);
        String config = configService.getConfig(dataId, group, 10);
        System.out.println(config);

    }
}

ok, 就可以获取nacos的配置信息了

四. nacos配置管理的模型

对于nacos配置管理, 通过namespace, group, dataId能够定位到一个配置集.

在这里插入图片描述

nacos的配置管理模型包含三部分: namespace, group, service/data Id. 通过配置管理模型, 我们可以定位到所需要的配置文件

其中service/data Id中. server是服务发现, dataId是配置管理.

1. 配置集(DataId)

  配置集就是上图的DataId

  在系统中, 通常一个配置文件, 就是一个配置集. 一个配置集可以包含系统的各种配置信息. 例如:一个配置集可能包含系统的数据源、连接池, 日志等级的配置信息。每个配置集都可以定义一个有意义的名称, 就是配置集的Id, 即Data Id

2. 配置项

  配置集中包含的一个个配置内容, 就是配置项. 他代表具体的可配置的参数. 通常以key=value的形式存在.

3. 配置分组(Group)

  配置分组就是上图中的Group. 配置分组是对配置集进行分组. 通过一个有意义的字符串(如: buy, trade)来表示. 不同的配置分组下可以有相同的配置集(Data ID). 当您在nacos上创建一个配置的时候, 如果未填写配置分组的名称, 则采用默认名称DEFAULT_GROUP.

  配置分组的常见场景有: 可用于区分不同的项目或应用. 例如: 学生管理系统的配置集可以定义一个group为:STUDENT_GROUP.

4 命名空间(Namespace)

  命名空间(namespace)可用于对不同的环境进行配置隔离. 例如: 可以隔离开发环境, 测试环境, 生成环境. 因为他们的配置可能各不相同. 或者是隔离不同的用户, 不同的开发人员使用同一个nacos管理各自的配置, 可通过namespace进行隔离. 不同的命名空间下, 可以存在相同名称的配置分组(Group)或配置项(Data Id)

最佳实践 通常我们可以这样定义namespace, group, dataid

  1. Namespace: 代表不同的环境, 如: 开发、测试, 生产等

  2. Group: 可以代表某个项目, 如XX医疗项目, XX电商项目

  3. DataId: 每个项目下往往有若干个工程, 每个配置集(DataId)是一个工程的主配置文件

在这里插入图片描述

结合已有的项目, 进行分析

五. 命名空间的管理

我们先来回顾一下上面的客户端实现. 在上面的客户端实现中,我们是没有定义命名空间的. 那么他会采用默认的命名空间public. 在这里插入图片描述

1. namespace的隔离设计

  • 按照环境来设计namespace: 开发, 测试, 生产    这样不同的环境的配置是相互隔离开的, 互不影响 在这里插入图片描述

  • 还可以按照多用户的方式来设计. 比如, 张三, 李四,王五, 他们看到的自己的内容是不一样的.

2. 命名空间的管理

创建命名空间 在这里插入图片描述

界面操作比较简单,不都说了

下面我创建了4个命名空间. 其中public和dev都有一个Data Id叫做test.demo.yml. 我要通过程序代码获取dev下的test.demo.yml配置文件. 在这里插入图片描述

模拟客户端获取nacos的命名空间为dev下的配置信息:

package com.lxl.org;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;

import java.util.Properties;

public class DemoTest {

    public static void main(String[] args) throws NacosException, InterruptedException {
        String dataId = "test.demo.yml";
        // 注意: 这里填的是命名空间的id
        String namespace = "dev";
        String group = "DEFAULT_GROUP";
        String serverAddr = "localhost:8848";

        Properties properties = new Properties();
        properties.setProperty("serverAddr", serverAddr);
        properties.setProperty("namespace", namespace);
        // 和nacos服务建立连接
        ConfigService configService = NacosFactory.createConfigService(properties);
        String config = configService.getConfig(dataId, group, 10);
        System.out.println(config);


        Thread.sleep(1000);
    }
}

需要指定要获取的配置是哪个命名空间下面的.

3. 查看历史版本

历史版本这里就说一点, 那就是可以回滚. 点击回滚, 就回滚到了某个版本的配置

4. 监听查询

在这里插入图片描述 想要监听开发环境下, 某个配置文件. 则课一下监听查询中查看哪些配置文件被监听了.

比如: 我们写一个demo, 监听dev下的test.demo.yaml配置文件

public static void main(String[] args) throws NacosException, InterruptedException {
       String dataId = "test.demo.yml";
       // 注意: 这里填的是命名空间的id
       String namespace = "a127e7f7-e37e-48fb-9968-cca7ef7c9f26";
       String group = "DEFAULT_GROUP";
       String serverAddr = "localhost:8848";

       Properties properties = new Properties();
       properties.setProperty("serverAddr", serverAddr);
       properties.setProperty("namespace", namespace);
       // 和nacos服务建立连接
       ConfigService configService = NacosFactory.createConfigService(properties);
       String config = configService.getConfig(dataId, group, 10);
       System.out.println(config);


       configService.addListener(dataId, group, new Listener() {
           @Override
           public Executor getExecutor() {
               return null;
           }

           @Override
           public void receiveConfigInfo(String s) {
               // 接收监听到的返回的配置信息
               System.out.println(s);
           }
       });

       Thread.sleep(1000000);
   }

写一个监听程序, 不停的进行监听. 一旦有配置发生变化, 立刻就可以通知过来.

5. 登录管理

nacos支持简单的登录功能, 默认的用户名/密码是: nacos/nacos.

修改默认用户名和密码的方法:

通过看源码可以知道, nacos用户加密使用的是BCrypt加密的方式. 因此,我们可以模拟一个BCrypt方法进行修改密码

  • 在项目中引入BCrypt 的jar包
 <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>5.1.4.RELEASE</version>
        </dependency>
 

然后写一个修改密码的方法

package com.lxl.org;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordHandler {
    public static void main(String[] args) {
        String encode = new BCryptPasswordEncoder().encode("123");
        System.out.println(encode);
    }
}

输出结果替换数据库中的密码即可

$2a$10$LW/6RKgceuALErDPcU8THOT5V1Ajc98jgo6N38oOX0Tvmce39hP4a

新加用户, 需要设置用户的用户名和角色

insert into users(username, password, enabled) VALUES ("lxl", "$2a$10$LW/6RKgceuALErDPcU8THOT5V1Ajc98jgo6N38oOX0Tvmce39hP4a", 1);
insert into roles(username, role) VALUES ('lxl', 'ROLE_ADMIN')

也可以在控制台修改

六. Nacos配置管理应用于分布式系统

下图展示了nacos集中管理多个配置服务的流程 在这里插入图片描述

  1. 用户通过nacos 服务的控制台对配置文件进行集中管理

  2. 各服务统一从nacos中获取各自的配置, 并监听配置的变化.


1. 模拟两个微服务请求一个注册中心的场景.

1. 在dev环境下, 新建两个配置文件. server1, server2 在这里插入图片描述

2. 创建一个简单的微服务架构. 采用spring cloud微服务架构. 创建一个parent工程, 引入公共的配置. 在创建两个微服务server1, server2 创建一个parent maven工程, 引入maven包

<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>

创建一个service1. 然后添加nacos的maven管理. 在添加bootstrap.yml配置文件, 最后增加启动类

<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. 这里需要注意的是默认查找的data Id是应用面+扩展名

server:
  port: 56010

spring:
  application:
    name: service1
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml
        namespace: dev
        group: TEST_GROUP
        # 查找默认的data Id --> 应用名 + 文件扩展名-->service1.yaml

最后增加启动类, 里面直接定义了一个controller, 获取配置信息

package com.lxl.www.service1;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

    /**
     *  采用注解的方式读取nacos配置信息
     */
    @Value("${common.config}")
    private String config1;


    /**
     * 定义一个controller
     */
    @GetMapping(value = "/config")
    public String getNacosConfig() {
        return config1;
    }
}

service2也是如此.

注意: nacos发布的时候, 要打开日志文件, 看看是否发布成功. 如果报异常, 可能发布不成功. 项目获取配置文件失败

在这里插入图片描述

这里客户端使用的是阿里提供的nacos客户端: spring-cloud-starter-alibaba-nacos-config

存在的问题:

当使用spring的注解@Value的时候, 我们发现, 在配置中心修改了配置文件的内容, 但是通过注解读取出来的内容没变. 这是什么愿意闹呢?其实, 配置文件修改了内容以后, 他是通知了服务端的, 之所以没改, 是因为@Value属性的原因, 他应该是有缓存了. 那么如果想动态获取修改后的配置文件, 有两种方式:

方式一: 使用properties.

获取配置的方式, 修改如下:

   @Autowired
    private ConfigurableApplicationContext applicationContext;

    /**
     * 定义一个controller
     */
    @GetMapping(value = "/config")
    public String getNacosConfig() {
        return applicationContext.getEnvironment().getProperty("common.config");
    }

方式二: @NacosValue

注意事项:

  • nacos的配置信息要写在bootstrap.yml中. 让其配置信息优先加载. (bootstrap.yml加载的时间要比application.yml早)

2. 扩展DataId, 多配置处理

如果有多个配置文件, 我们可以使用扩展配置的方式, 添加多个配置文件

扩展配置id, 第一个扩展的配置id
ext-config[0]:
    data-id: ext-config-common01.yml

ext-config[1]:
    data-id: ext-config-common02.yml
    group: GLOBAL_GROUP

ext-config[2]:
    data-id: ext-config-common03.yml
    group: REFRESH_GROUP
    refresh: true #配置修改, 是否刷新          

第一个配置, 只有一个data-id. 没有group, 采用默认的DEFAULT_GROUP.

第二个扩展配置. 定义了一个GLOBAL_GROUP. 全局配置

第三个扩展配置: 定义为一个自动刷新的GROUP, 并设置自动刷新属性为true 接下来我们在控制台添加这三个文件 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

修改接口获取配置信息

    /**
     * 定义一个controller
     */
    @GetMapping(value = "/config")
    public String getNacosConfig() {
        String p1 = applicationContext.getEnvironment().getProperty("common.config");
        String p2 = applicationContext.getEnvironment().getProperty("common.ext1");
        String p3 = applicationContext.getEnvironment().getProperty("common.ext2");
        String p4 = applicationContext.getEnvironment().getProperty("common.ext3");
        return p1 + "+" + p2 + "+" + p3 + "+" + p4;
    }

我们可以看到打印出来的效果 在这里插入图片描述

这时, 在控制台修改配置文件, 我们发现common.config会改变. common.ext3会改变. 其他两个不会自动更新

总结: 默认配置是可以自动刷新的. 在扩展配置中, 只有增加了属性refresh:true, 才会自动刷新

3. 共享Data Id

我们可以设置共享data id, 设置方法如下:

在这里插入图片描述

设置共享的data id. 我们设置了三个文件. 启动项目, 运行结果如下

在这里插入图片描述

我们发现, 有两个是null. 为什么是null呢? 因为使用这种方式配置, 只能第一个文件生效, 因此, 如果想要配置多个扩展文件, 还要使用扩展dataId的方式.

4. 配置Data Id的优先级

目前有三种设置Data Id的方式

  • 默认的data id. 项目名+扩展名的方式.
  • 使用ext-config[0] 设置扩展配置
  • 使用shared-dataids: 设置共享配置.

那么, 他们三个的优先级是什么样的呢?

默认配置 > ext-config > shared-dataids 如果有多个ext-config扩展配置, 谁的优先级高呢? n的个数越大, 优先级越高.....

ext-config[n] > ext-config[2] > ext-config[1] > ext-config[0]

5. 关闭Nacos配置

如果不想要使用nacos配置了, 那么可以使之enable属性为false

七. Nacos集群部署

通常我们在生成环境不可能只有一台nacos. 为了保证高可用性, 我们会配置多台nacos.

要求: 配置3台或以上nacos服务

下面我们来模拟三台nacos服务集群

第一步: 解压三个nacos服务 在这里插入图片描述

第二步: 修改配置文件

  1. 修改端口号. 分别设置为8848, 8849, 8850

在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

2. 添加本地服务的ip地址

给三个服务都增加下面这个配置内容: 设置本机的ip地址

nacos.inetutils.ip-address=127.0.0.1

3. 设置三个nacos的集群关系

修改cluster.conf.example文件为cluster.conf

并在里面添加如下内容 在这里插入图片描述

第四步: 启动三台服务器. 以集群的模式启动 ./start.sh -m cluster 然后, 在控制他查看集群, 有一台主, 两台从 在这里插入图片描述

第五步 在项目中配置nacos集群 在这里插入图片描述

注意: 多个配置之间不能带空格.

重启项目. 访问接口返回内容 在这里插入图片描述

这里面, 我们可以停掉任何一台nacos服务. 只要还有一个能运行, 服务就可以访问通