下面將研究以下幾個問題:
- nacos的角色: nacos是如何工作的? 在集群中扮演什么樣的角色?
- 修改nacos配置數(shù)據(jù)庫: 我們在控制臺配置的信息, 默認(rèn)是寫到nacos的默認(rèn)數(shù)據(jù)庫中, 不方便管理, 因此我們設(shè)置一個自己的數(shù)據(jù)庫, 進行管理操作
- 在控制臺配置nacos配置
- nacos配置管理的模型: 基本概念,namespace, group, data id及其用法
- 命名空間的管理, namespace的使用
- Nacos配置管理應(yīng)用于分布式系統(tǒng)
- 7.Nacos集群部署
一. nacos的角色
在這里插入圖片描述
這張圖說明了nacos是一個單獨的服務(wù)器, 用戶修改或者發(fā)布配置信息, 會通知下游的服務(wù)器. 下游的服務(wù)器也可以根據(jù)一定的規(guī)則讀取配置中心的配置信息.
讓nacos成為spring cloud集群的一部分
啟動nacos服務(wù)
將nacos納為spring cloud微服務(wù)的一部分
將spring cloud其他應(yīng)用服務(wù)注冊到nacos上.
二. 修改nacos配置數(shù)據(jù)庫
下面驗證服務(wù)的可用性
1. 啟動nacos
./startup.sh -m standalone
注意: 這里一定要單機模式啟動, 默認(rèn)是集群模式, 我們現(xiàn)在沒有在集群中, 會報異常.
2 往配置中心發(fā)布配置
nacos是一個服務(wù), 他對外也提供了很多接口, 其中一個是添加配置的接口. 我們模擬這個接口進行配置:
curl -X POST "http://localhost:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"
看到返回結(jié)果是true. 然后刷新控制臺, 可以看到如下
3. 從配置中心獲取配置
curl -X GET "http://localhost:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
這個命令就是獲取配置
獲取helloworld內(nèi)容
4. 改變nacos配置數(shù)據(jù)的存儲位置
我們把配置信息添加到nacos, 那么,他是如何保存的呢? nacos某一個默認(rèn)的自帶數(shù)據(jù)庫, 這個數(shù)據(jù)庫不方便操作和查找. 因此我們將其替換為自己的mysql數(shù)據(jù)庫
1. 準(zhǔn)備一個mysql數(shù)據(jù)庫
因為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. 創(chuàng)建一個nacos_config的數(shù)據(jù)庫
3. 初始化nacos_config表結(jié)構(gòu)
在這里找到配置文件: ${nacosHome}/conf/nacos-mysql.
4. 修改application.properties配置文件
然后重新啟動.
在執(zhí)行上面的寫配置
數(shù)據(jù)庫里生成了一條配置信息:
三. nacos配置
1. 在控制臺添加配置
Data ID: nacos-simple-demo.yaml
Group: DEFAULT_GROUP
配置格式: YAML
配置內(nèi)容:
common
config: something
將以上信息在控制臺配置好了
以上就是在nacos服務(wù)端建好了配置信息
2. 模擬nacos客戶端--獲取nacos服務(wù)端配置
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服務(wù)建立連接
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是服務(wù)發(fā)現(xiàn), dataId是配置管理.
1. 配置集(DataId)
配置集就是上圖的DataId
在系統(tǒng)中, 通常一個配置文件, 就是一個配置集. 一個配置集可以包含系統(tǒng)的各種配置信息. 例如:一個配置集可能包含系統(tǒng)的數(shù)據(jù)源万伤、連接池, 日志等級的配置信息申窘。每個配置集都可以定義一個有意義的名稱, 就是配置集的Id, 即Data Id
2. 配置項
配置集中包含的一個個配置內(nèi)容, 就是配置項. 他代表具體的可配置的參數(shù). 通常以key=value的形式存在.
3. 配置分組(Group)
配置分組就是上圖中的Group. 配置分組是對配置集進行分組. 通過一個有意義的字符串(如: buy, trade)來表示. 不同的配置分組下可以有相同的配置集(Data ID). 當(dāng)您在nacos上創(chuàng)建一個配置的時候, 如果未填寫配置分組的名稱, 則采用默認(rèn)名稱DEFAULT_GROUP.
配置分組的常見場景有: 可用于區(qū)分不同的項目或應(yīng)用. 例如: 學(xué)生管理系統(tǒng)的配置集可以定義一個group為:STUDENT_GROUP.
4 命名空間(Namespace)
命名空間(namespace)可用于對不同的環(huán)境進行配置隔離. 例如: 可以隔離開發(fā)環(huán)境, 測試環(huán)境, 生成環(huán)境. 因為他們的配置可能各不相同. 或者是隔離不同的用戶, 不同的開發(fā)人員使用同一個nacos管理各自的配置, 可通過namespace進行隔離. 不同的命名空間下, 可以存在相同名稱的配置分組(Group)或配置項(Data Id)
最佳實踐
通常我們可以這樣定義namespace, group, dataid
Namespace: 代表不同的環(huán)境, 如: 開發(fā)、測試曙旭, 生產(chǎn)等
Group: 可以代表某個項目, 如XX醫(yī)療項目, XX電商項目
DataId: 每個項目下往往有若干個工程, 每個配置集(DataId)是一個工程的主配置文件
結(jié)合已有的項目, 進行分析
五. 命名空間的管理
我們先來回顧一下上面的客戶端實現(xiàn). 在上面的客戶端實現(xiàn)中,我們是沒有定義命名空間的. 那么他會采用默認(rèn)的命名空間public.
1. namespace的隔離設(shè)計
-
按照環(huán)境來設(shè)計namespace: 開發(fā), 測試, 生產(chǎn)
這樣不同的環(huán)境的配置是相互隔離開的, 互不影響
在這里插入圖片描述 還可以按照多用戶的方式來設(shè)計. 比如, 張三, 李四,王五, 他們看到的自己的內(nèi)容是不一樣的.
2. 命名空間的管理
創(chuàng)建命名空間
界面操作比較簡單,不都說了
下面我創(chuàng)建了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服務(wù)建立連接
ConfigService configService = NacosFactory.createConfigService(properties);
String config = configService.getConfig(dataId, group, 10);
System.out.println(config);
Thread.sleep(1000);
}
}
需要指定要獲取的配置是哪個命名空間下面的.
3. 查看歷史版本
歷史版本這里就說一點, 那就是可以回滾. 點擊回滾, 就回滾到了某個版本的配置
4. 監(jiān)聽查詢
想要監(jiān)聽開發(fā)環(huán)境下, 某個配置文件. 則課一下監(jiān)聽查詢中查看哪些配置文件被監(jiān)聽了.
比如: 我們寫一個demo, 監(jiān)聽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服務(wù)建立連接
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) {
// 接收監(jiān)聽到的返回的配置信息
System.out.println(s);
}
});
Thread.sleep(1000000);
}
寫一個監(jiān)聽程序, 不停的進行監(jiān)聽. 一旦有配置發(fā)生變化, 立刻就可以通知過來.
5. 登錄管理
nacos支持簡單的登錄功能, 默認(rèn)的用戶名/密碼是: nacos/nacos.
修改默認(rèn)用戶名和密碼的方法:
通過看源碼可以知道, 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);
}
}
輸出結(jié)果替換數(shù)據(jù)庫中的密碼即可
$2a$10$LW/6RKgceuALErDPcU8THOT5V1Ajc98jgo6N38oOX0Tvmce39hP4a
新加用戶, 需要設(shè)置用戶的用戶名和角色
insert into users(username, password, enabled) VALUES ("lxl", "$2a$10$LW/6RKgceuALErDPcU8THOT5V1Ajc98jgo6N38oOX0Tvmce39hP4a", 1);
insert into roles(username, role) VALUES ('lxl', 'ROLE_ADMIN')
也可以在控制臺修改
六. Nacos配置管理應(yīng)用于分布式系統(tǒng)
下圖展示了nacos集中管理多個配置服務(wù)的流程
用戶通過nacos 服務(wù)的控制臺對配置文件進行集中管理
各服務(wù)統(tǒng)一從nacos中獲取各自的配置, 并監(jiān)聽配置的變化.
1. 模擬兩個微服務(wù)請求一個注冊中心的場景.
1. 在dev環(huán)境下, 新建兩個配置文件. server1, server2
2. 創(chuàng)建一個簡單的微服務(wù)架構(gòu). 采用spring cloud微服務(wù)架構(gòu).
創(chuàng)建一個parent工程, 引入公共的配置. 在創(chuàng)建兩個微服務(wù)server1, server2
創(chuàng)建一個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>
創(chuàng)建一個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. 這里需要注意的是默認(rèn)查找的data Id是應(yīng)用面+擴展名
server:
port: 56010
spring:
application:
name: service1
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yaml
namespace: dev
group: TEST_GROUP
# 查找默認(rèn)的data Id --> 應(yīng)用名 + 文件擴展名-->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發(fā)布的時候, 要打開日志文件, 看看是否發(fā)布成功. 如果報異常, 可能發(fā)布不成功. 項目獲取配置文件失敗
這里客戶端使用的是阿里提供的nacos客戶端: spring-cloud-starter-alibaba-nacos-config
存在的問題:
當(dāng)使用spring的注解@Value的時候, 我們發(fā)現(xiàn), 在配置中心修改了配置文件的內(nèi)容, 但是通過注解讀取出來的內(nèi)容沒變. 這是什么愿意鬧呢?其實, 配置文件修改了內(nèi)容以后, 他是通知了服務(wù)端的, 之所以沒改, 是因為@Value屬性的原因, 他應(yīng)該是有緩存了. 那么如果想動態(tài)獲取修改后的配置文件, 有兩種方式:
方式一: 使用properties.
獲取配置的方式, 修改如下:
@Autowired
private ConfigurableApplicationContext applicationContext;
/**
* 定義一個controller
*/
@GetMapping(value = "/config")
public String getNacosConfig() {
return applicationContext.getEnvironment().getProperty("common.config");
}
方式二: @NacosValue
注意事項:
- nacos的配置信息要寫在bootstrap.yml中. 讓其配置信息優(yōu)先加載. (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. 沒有g(shù)roup, 采用默認(rèn)的DEFAULT_GROUP.
第二個擴展配置. 定義了一個GLOBAL_GROUP. 全局配置
第三個擴展配置: 定義為一個自動刷新的GROUP, 并設(shè)置自動刷新屬性為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;
}
我們可以看到打印出來的效果
這時, 在控制臺修改配置文件, 我們發(fā)現(xiàn)common.config會改變. common.ext3會改變. 其他兩個不會自動更新
總結(jié): 默認(rèn)配置是可以自動刷新的. 在擴展配置中, 只有增加了屬性refresh:true, 才會自動刷新
3. 共享Data Id
我們可以設(shè)置共享data id, 設(shè)置方法如下:
設(shè)置共享的data id. 我們設(shè)置了三個文件. 啟動項目, 運行結(jié)果如下
我們發(fā)現(xiàn), 有兩個是null. 為什么是null呢? 因為使用這種方式配置, 只能第一個文件生效, 因此, 如果想要配置多個擴展文件, 還要使用擴展dataId的方式.
4. 配置Data Id的優(yōu)先級
目前有三種設(shè)置Data Id的方式
- 默認(rèn)的data id. 項目名+擴展名的方式.
- 使用ext-config[0] 設(shè)置擴展配置
- 使用shared-dataids: 設(shè)置共享配置.
那么, 他們?nèi)齻€的優(yōu)先級是什么樣的呢?
默認(rèn)配置 > ext-config > shared-dataids
如果有多個ext-config擴展配置, 誰的優(yōu)先級高呢? n的個數(shù)越大, 優(yōu)先級越高.....
ext-config[n] > ext-config[2] > ext-config[1] > ext-config[0]
5. 關(guān)閉Nacos配置
如果不想要使用nacos配置了, 那么可以使之enable屬性為false
七. Nacos集群部署
通常我們在生成環(huán)境不可能只有一臺nacos. 為了保證高可用性, 我們會配置多臺nacos.
要求: 配置3臺或以上nacos服務(wù)
下面我們來模擬三臺nacos服務(wù)集群
第一步: 解壓三個nacos服務(wù)
第二步: 修改配置文件
- 修改端口號. 分別設(shè)置為8848, 8849, 8850
2. 添加本地服務(wù)的ip地址
給三個服務(wù)都增加下面這個配置內(nèi)容: 設(shè)置本機的ip地址
nacos.inetutils.ip-address=127.0.0.1
3. 設(shè)置三個nacos的集群關(guān)系
修改cluster.conf.example文件為cluster.conf
并在里面添加如下內(nèi)容
第四步: 啟動三臺服務(wù)器. 以集群的模式啟動
./start.sh -m cluster
然后, 在控制他查看集群, 有一臺主, 兩臺從
第五步 在項目中配置nacos集群
注意: 多個配置之間不能帶空格.
重啟項目. 訪問接口返回內(nèi)容
這里面, 我們可以停掉任何一臺nacos服務(wù). 只要還有一個能運行, 服務(wù)就可以訪問通