下面將研究以下幾個問題:
1. nacos的角色: nacos是如何工作的? 在集群中扮演什么樣的角色?
2. 修改nacos配置數據庫: 我們在控制台配置的信息, 默認是寫到nacos的默認數據庫中, 不方便管理, 因此我們設置一個自己的數據庫, 進行管理操作
3. 在控制台配置nacos配置
4. nacos配置管理的模型: 基本概念,namespace, group, data id及其用法
5. 命名空間的管理, namespace的使用
6. Nacos配置管理應用於分布式系統
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.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下的配置信息:
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>
然后寫一個修改密碼的方法
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. 模擬兩個微服務請求一個注冊中心的場景.
- 在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, 獲取配置信息
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服務. 只要還有一個能運行, 服務就可以訪問通
