下面将研究以下几个问题:
- nacos的角色: nacos是如何工作的? 在集群中扮演什么样的角色?
- 修改nacos配置数据库: 我们在控制台配置的信息, 默认是写到nacos的默认数据库中, 不方便管理, 因此我们设置一个自己的数据库, 进行管理操作
- 在控制台配置nacos配置
- nacos配置管理的模型: 基本概念,namespace, group, data id及其用法
- 命名空间的管理, namespace的使用
- Nacos配置管理应用于分布式系统
- 7.Nacos集群部署
一. nacos的角色
这张图说明了nacos是一个单独的服务器, 用户修改或者发布配置信息, 会通知下游的服务器. 下游的服务器也可以根据一定的规则读取配置中心的配置信息.
让nacos成为spring cloud集群的一部分
启动nacos服务
将nacos纳为spring cloud微服务的一部分
将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/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
Namespace: 代表不同的环境, 如: 开发、测试, 生产等
Group: 可以代表某个项目, 如XX医疗项目, XX电商项目
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集中管理多个配置服务的流程
用户通过nacos 服务的控制台对配置文件进行集中管理
各服务统一从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服务
第二步: 修改配置文件
- 修改端口号. 分别设置为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服务. 只要还有一个能运行, 服务就可以访问通