[TOC]
使用Nacos管理配置
爲什麼要需要配置管理?
在微服務架構中,每個微服務都有可能會存在多個實例,爲了保證同一微服務不同實例的配置文件內容一致,我們就需要有一個服務可以對微服務項目的配置文件進行統一管理,通常我們將其稱之爲統一配置管理中心。因爲如果配置文件的內容不一致,有可能會導致同一微服務的不同實例在行爲上發生差異,從而導致一些錯誤。
除此之外,在企業開發中還要求項目在不同環境使用不同配置,以及可以在不重啓服務的情況下實現配置文件的動態刷新,爲了實現這些需求我們也得使用到統一配置管理中心
目前業界比較流行的統一配置管理中心組件有Spring Cloud的Config、Spring Cloud Alibaba的Nacos以及攜程開源的Apollo。本文主要介紹Nacos作爲統一配置管理中心的使用,關於其他配置中心組件以及Nacos的基本使用可以參考如下文章:
接下來,我們看看如何使用Nacos管理配置文件,現在我有一段接口代碼如下:
@RestController
@RequiredArgsConstructor
public class TestController {
@Value("${your.configuration}")
private String yourConfiguration;
@GetMapping("/getConfiguration")
public String getConfiguration(){
return yourConfiguration;
}
}
這段代碼讀取了一個配置項,此時該配置項存在於項目的application.yml
文件中,如下:
your:
configuration: your_value
那麼我們要如何使用Nacos管理這段配置呢?首先需要爲項目整合Nacos配置管理的功能,在pom.xml文件中添加如下依賴:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- Tips:該項目使用的Spring Cloud版本爲
Greenwich.SR1
,Alibaba的版本爲2.1.0.RELEASE
然後在resources
目錄下新建一個名爲bootstrap.yml
的文件,添加如下配置項:
spring:
cloud:
nacos:
config:
# 指定作爲配置中心的nacos server地址
server-addr: 127.0.0.1:8848
# 配置文件格式
file-extension: yaml
discovery:
# 指定作爲服務註冊中心的nacos server地址
server-addr: 127.0.0.1:8848
application:
name: content-center
profiles:
active: dev
到Nacos的管理頁面的“配置列表”中新建配置:
新建的配置內容如下圖:
注意,這裏的Data ID是具有一定格式的,需要與項目中的配置對應上。如上圖中的:content-center-dev.yaml,其中content-center是微服務名稱,dev是環境,yaml是配置文件的格式。這裏簡單整理成了一張對照圖,如下:
- Tips:這裏文件Data ID的後綴不一定必須是
.yaml
,也可以是.yml
,因爲這兩種後綴其實都是表示同一種文件格式
到目前爲止,我們就已經爲項目整合了Nacos的配置管理功能,並在Nacos Server上新建了項目所需的配置。此時就可以將之前配置在application.yml
文件中的配置項給刪除掉。然後啓動項目,訪問/getConfiguration
接口,返回結果如下則代表整合成功:
動態刷新配置及回滾
在實際的企業開發中,我們通常希望在配置中心上修改了配置項後,不需要重啓項目就能夠實現實時的動態配置刷新。對於整合了Nacos的微服務項目來說,想要實現這個功能是很簡單的,只需要在讀取了配置屬性的類上加上@RefreshScope
註解即可。如下示例:
// 該註解用於標識哪些地方需要動態刷新配置,可以寫在類及方法上
@RefreshScope
@RestController
@RequiredArgsConstructor
public class TestController {
@Value("${your.configuration}")
private String yourConfiguration;
@GetMapping("/getConfiguration")
public String getConfiguration(){
return yourConfiguration;
}
}
添加完該註解後,重啓項目,然後到Nacos上修改之前配置項的值,點擊發布後會有一個內容比較的提示,可以看到我將之前的your_value
改成了my_value
:
點擊確認發佈後,然後再訪問/getConfiguration
接口,返回的就是修改後的值了,而此時我們並沒有重啓項目:
除了以上所介紹的動態刷新之外,還有一個比較重要的功能:配置回滾。如果有一天修改某些配置項併發布後發現手滑改錯了,導致項目運行出問題,那麼就可以使用回滾功能可以幫助我快速回滾到某個特定的版本上。我們可以在Nacos的“歷史版本”頁面中查詢指定配置的歷史版本,如下圖:
點擊“詳情”可以查看到具體的配置內容:
點擊“回滾配置”則可以回滾到指定的歷史版本,例如我這裏就回滾到初始版本:
提示回滾成功後訪問/getConfiguration
接口,會發現報錯了:
這是目前Nacos 1.1版本的一個Bug,當選擇回滾的版本是最初版本時就會發生這個問題。官方稱會在1.2版本中修復該問題,而我目前使用的是最新的1.1.3版本,仍屬於1.1版本(2019-09-10),所以該bug還存在。相關的issues如下:
在1.1版本下,只要回滾的不是初始版本則不會觸發這個bug,回滾其他版本是可以正常使用的,所以該問題注意一下即可規避
注:觸發該bug後,配置內容由於回滾失敗會丟失,此時需要重新創建配置
配置共享
以上我們介紹了Nacos作爲配置中心的基本使用,而本小節將介紹相同應用下的配置共享,所謂的配置共享就是一些配置項可以在相同應用的不同環境中進行共享。
例如以上示例中的${your.configuration}
配置項,我們希望在所有的環境下該配置項都是相同的值,而又不想在每個環境的配置文件裏面都配置一遍,也就是說這個配置項是所有環境通用的,那麼這時候就需要將該配置項在所有環境中共享了。
想要實現配置共享只需要新建一個配置文件即可,首先我們來看一段日誌信息,當我們啓動項目時,控制檯會出輸出如下一段日誌信息:
2019-09-11 20:47:42.197 INFO 13778 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='content-center-dev.yaml'}, NacosPropertySource {name='content-center.yaml'}]}
從該日誌信息可以看到,項目在啓動時會到Nacos上讀取兩個配置文件,即content-center-dev.yaml
和content-center.yaml
,其中content-center-dev.yaml
裏保存的是開發環境下特定的配置,而content-center.yaml
裏保存的則是所有環境下通用的配置。項目在啓動時具體讀取哪個環境的配置文件是由bootstrap.yml
文件中的spring.profiles.active
配置項所決定的。
既然我們知道保存在content-center.yaml
裏的配置項會在所有環境中共享,那麼只需要到Nacos上新建這個配置文件即可。如下示例:
新建完成後,修改項目中的spring.profiles.active
爲其他環境,然後重啓項目,此時訪問/getConfiguration
接口,可以看到返回的是通用配置文件裏所配置的值:
- Tips:特定環境下的配置優先級高於通用環境配置,例如
${your.configuration}
配置項同時存在於content-center-dev.yaml
和content-center.yaml
中,若spring.profiles.active
的值爲dev
,那麼讀取的將是content-center-dev.yaml
裏所配置的值。
以上介紹了相同應用在不同環境下的配置共享,但如何實現不同應用之間的配置共享呢?例如我們經常會遇到微服務A和微服務B的數據庫配置是一樣的,如果能將這段相同的配置在這兩個服務之間共享,那麼就可以省去一些重複的工作。
目前Nacos提供了兩種方式可以實現不同應用之間的配置共享,第一種方式是使用shared-dataids
。接下來我們進行一個簡單的演示,首先需要到Nacos上創建一些共享配置,如下示例:
其中common1.yaml
配置內容如下:
common1:
configuration1: common1_value
common2.yaml
配置內容如下:
common2:
configuration2: common2_value
創建共享配置完成後,修改項目中的bootstrap.yml
文件如下:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
# 指定共享配置的DataId,多個使用,分隔
# 越靠後,優先級越高;common2.yml > common1.yaml
# .yaml後綴不能少,目前只支持yaml/properties
shared-dataids: common1.yaml,common2.yaml
# 指定哪些共享配置支持動態刷新,多個使用,分隔
refreshable-dataids: common1.yaml
server-addr: 127.0.0.1:8848
file-extension: yaml
application:
name: content-center
profiles:
active: dev
從以上的配置示例可以看出,其實shared-dataids
的主要作用就是用來指定共享配置的Data ID,使得該微服務可以讀取這些共享配置。同理,其他微服務若想讀取這些共享配置,只需在項目的bootstrap.yml
文件中添加相應的shared-dataids
配置即可,如此一來就實現了多個微服務之間的配置共享。
然後我們來寫兩個簡單的接口驗證一下是否能正常讀取這兩個共享配置的值,代碼如下:
@RefreshScope
@RestController
@RequiredArgsConstructor
public class TestController {
@Value("${common1.configuration1}")
private String common1Configuration;
@Value("${common2.configuration2}")
private String common2Configuration;
@GetMapping("/getCommonConfiguration1")
public String getCommonConfiguration1() {
return common1Configuration;
}
@GetMapping("/getCommonConfiguration2")
public String getCommonConfiguration2() {
return common2Configuration;
}
}
啓動項目,訪問結果如下:
第二種方式也是差不多的,只不過使用的配置項是ext-config
,修改項目中的bootstrap.yml
文件如下:
spring:
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
ext-config:
# 需共享的DataId,yaml後綴不能少,目前只支持yaml/properties
# 越靠後,優先級越高 優先級common2.yaml > common1.yaml
- data-id: common1.yaml
# common1.yaml所在的group
group: DEFAULT_GROUP
# 是否允許刷新,默認false
refresh: true
- data-id: common2.yaml
group: DEFAULT_GROUP
refresh: true
application:
name: content-center
profiles:
active: dev
ext-config
提供了較爲細化的配置方式,並且可以指定配置組。到目前爲止,我們介紹了三種從Nacos上讀取配置的方式,其優先級如下:
shared-dataids < ext-config < 自動
除此之外,當存在相同的遠程配置和本地配置時,遠程配置優先級要高於本地配置文件。但可以通過添加如下配置調整,需要注意的是這段配置需要放在遠程配置纔會生效:
spring:
cloud:
config:
# 是否允許本地配置覆蓋遠程配置,默認true
allow-override: true
# 是否一切以本地配置爲準,默認false
override-none: false
# 系統環境變量或系統屬性才能覆蓋遠程配置文件的配置
# 本地配置文件中配置的優先級低於遠程配置,默認true
override-system-properties: true
爲什麼要使用bootstrap.yml
在介紹爲項目整合Nacos做配置管理服務的時候,示例裏將Nacos Config的相關配置都寫在一個bootstrap.yml
文件裏,但是爲什麼要使用bootstrap.yml
呢?使用application.yml
不可以嗎?
這是其實是因爲bootstrap.yml
會被優先讀取,也就是說如果項目裏同時存在一個bootstrap.yml
和一個application.yml
的話,那麼bootstrap.yml
將會優先於application.yml
被Spring Boot讀取。這樣才能實現連接外部的配置管理服務器,從遠程讀取一些必要的配置,避免項目在啓動時缺失必要配置項而導致啓動失敗。
這裏實際涉及到一個引導上下文的概念,它是ApplicationContext
的父上下文,並且是由Spring Cloud提供的, 它所在的位置如下圖所示:
引導上下文在prepareEnvironment
的階段就會被創建,創建時會讀取bootstrap.yml
的內容作爲引導配置, 因此bootstrap.yml
優先於application.yml
加載。引導上下文與操作系統的引導程序非常類似,而bootstrap.yml
就相當於設置引導程序的相關指令。
關於Nacos的數據持久化
Nacos會將數據持久化到本地,當Nacos作爲服務發現組件時,默認會將服務的註冊信息存儲在如下目錄中:
類Unix系統:~/nacos/naming
windows系統:C:\用戶\{用戶名}\nacos\naming
具體文件如下圖所示:
打開其中一個文件,可以看到服務註冊信息的格式如下:
{
"metadata": {},
"dom": "DEFAULT_GROUP@@content-center",
"cacheMillis": 10000,
"useSpecifiedURL": false,
"hosts": [],
"name": "DEFAULT_GROUP@@content-center",
"checksum": "f797b857f5312a616a875924ecf6481a",
"lastRefTime": 1564815242804,
"env": "",
"clusters": ""
}
當Nacos作爲配置中心時,配置數據會分爲兩份並存儲在兩個地方,其中一份存儲在內嵌的derby數據庫中,這是Apache開源的一個完全由Java編寫的內嵌數據庫,而derby會有一個數據目錄,如下:
$NACOS_HOME/data/derby-data
我們可以使用IDEA連接derby來查看相關的數據表及存儲內容,在右邊菜單欄中點開Database -> 點擊+符號添加數據庫連接 -> Data Source -> Apache Derby。如下圖所示:
注意,此時需要將Nacos Server給停止掉,否則是無法連接的。停止Nacos Server之後,填寫相關的連接信息,Path填的是derby的數據目錄,用戶和密碼默認都是nacos。如下圖所示:
連接成功後,可以看到derby中的數據表如下:
其中CONFIG_INFO
表存儲了配置數據,打開該表可以看到內容如下:
需要注意的是derby並不能用於生產環境,因爲它是一個內嵌數據庫,無法實現高可用和集羣部署,所以一般搭建生產可用的Nacos時會將數據庫改爲使用MySQL等非內嵌數據庫。
而另一份數據存儲在如下目錄,主要是一些快照等數據:
類Unix系統:~/nacos/config
windows系統:C:\用戶\{用戶名}\nacos\config
快照主要用於提升性能以及做容災備份,具體文件如下圖所示: