Nacos 基礎教程

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母簡稱,一個更易於構建雲原生應用的動態服務發現配置管理服務管理平臺

Github地址:https://github.com/alibaba/nacos.
官網地址:https://nacos.io/zh-cn/docs.

一、背景

傳統的單體的服務業務模塊之間直接內部通過service接口調用,隨着業務規模的發展,各業務模塊內部的需求粒度更精細、更獨立、更深入,此時如果所有業務代碼仍然集成在同一個項目裏,則造成代碼臃腫、難維護、甚至啓動加載時間也會超慢。

爲此需要對項目做業務拆分,將原本的項目按業務模塊進行細化拆分,分爲多個獨立的微服務。這些獨立的微服務可以有自己的IP和端口,可以集羣部署,可以再次甚至多次細化拆分。

拆分之後的各服務之間是單獨的進程,服務之間需要交流,則需要網絡傳輸的方式進行數據交互和信息交換,因此產生了傳統的 RPC 遠程調用框架。

在傳統的 RPC 遠程調用框架中,管理每個服務與服務之間依賴關係比較複雜、管理比較複雜。

我們需要記錄對方服務的IP和端口,集羣模式下還需要設置多個IP,如果調用的服務很多,單純的維護這些信息就會造成配置問題件很繁瑣。而且無法動態應對服務地址的變更,或服務機器量的變更。

二、服務發現

所以需要使用服務治理,管理服務於服務之間依賴關係,可以實現服務調用、負載均衡、容錯等,實現服務發現與註冊,在此背景下,服務註冊中心就應用而生了。

服務發現是微服務架構體系中最關鍵的組件之一。如果嘗試着用手動的方式來給每一個客戶端來配置所有服務提供者的服務列表是一件非常困難的事,而且也不利於 服務的動態擴縮容。Nacos Discovery Starter 可以幫助您將服務自動註冊到 Nacos 服務端並且能夠動態感知和刷新某個服務實例的服務列表。除此之外,Nacos Discovery Starter 也將服務實例自身的一些元數據信息-例如 host,port, 健康檢查URL,主頁等-註冊到 Nacos 。

共涉及到以下 3 個角色:

  1. 服務註冊中心(Register Service):它是一個 Nacos Server,可以爲服務提供者和服務消費者提供服務註冊和發現功能。
  2. 服務提供者(Provider Service):它是一個 Nacos Client,用於對外服務。它將自己提供的服務註冊到服務註冊中心,以供服務消費者發現和調用。
  3. 服務消費者(Consumer Service):它是一個 Nacos Client,用於消費服務。它可以從服務註冊中心獲取服務列表,調用所需的服務。

Nacos 實現服務註冊與發現的流程如下:

  1. 服務提供者 Nacos Client 啓動時,會把服務以服務名(spring.application.name)的方式註冊到服務註冊中心(Nacos Server);
  2. 服務消費者 Nacos Client 啓動時,也會將自己的服務註冊到服務註冊中心;
  3. 服務消費者在註冊服務的同時,它還會從服務註冊中心獲取一份服務註冊列表信息,該列表中包含了所有註冊到服務註冊中心上的服務的信息(包括服務提供者和自身的信息);
  4. 在獲取了服務提供者的信息後,服務消費者通過 HTTP 或消息中間件遠程調用服務提供者提供的服務。

1.主流注冊中心的比較

目前主流的服務註冊中心主要包括Eureka、Consul、ZooKeeper、Nacos等。

選擇 AP 還是 CP ?
服務註冊中心到底選用 CP 模型還是 AP 模型,還是要依照業務場景進行決定,如果對數據一致性要求較高,且可以容忍一定時間的不可用,就選用 CP 模型。反之,如果可以容忍一定時間的數據不一致性,但不能容忍不可用現象發生,則要選用 AP 模型。
道理是這樣的,但是目前市場上大部分的服務還是選擇AP的較多,爲什麼?
對於服務發現來說,針對同一個服務,即使註冊中心的不同節點保存的服務提供者信息不盡相同,也並不會造成災難性的後果。因爲對於服務消費者來說,能消費纔是最重要的,消費者雖然拿到可能不正確的服務實例信息後嘗試消費一下,也要勝過因爲無法獲取實例信息而不去消費,導致系統異常要好。從這一點上來說,分佈式服務註冊中心AP模式要更優於CP模式。這也是爲什麼越來越多的人拋棄Zookeeper的原因所在。

對於Nacos 而言,如果註冊 Nacos 的 client 節點註冊時 ephemeral=true,那麼 Nacos 集羣對這個 client 節點的效果就是 AP,採用 distro 協議實現;而註冊Nacos 的 client 節點註冊時ephemeral=false,那麼 Nacos 集羣對這個節點的效果就是 CP 的,採用 Raft 協議實現。根據 client 註冊時的屬性,AP、CP同時混合存在,只是對不同的 client 節點效果不同。Nacos 可以很好的解決不同場景的業務需求。

# false爲永久實例,true表示臨時實例開啓,註冊爲臨時實例,默認是true
spring.cloud.nacos.discovery.ephemeral=true

2. 選擇Nacos的理由

  • 簡單易⽤:簡單的數據模型,標準的 restfulAPI,易用的控制檯,豐富的使用文檔。
  • 高可用:99.9% 高可用,同時支持CP和AP,歷經阿里巴巴 10 年生產驗證的內部產品,支持具有數百萬服務的大規模場景。
  • 產品用戶多: 社區活躍,服務於衆多互聯網級公司客戶。
  • 實時高性能:數據變更毫秒級推送生效;(1w 級,SLA 承諾 1w 實例上下線 1s,99.9% 推送完成;10w級,SLA 承諾 1w 實例上下線 3s,99.9% 推送完成;100w 級別,SLA 承諾 1w 實例上下線 9s 99.9% 推送完成。)
  • 生態豐富:Nacos 幾乎支持所有主流語言,也對微服務生態活躍的技術做了無縫的支持,是 Java 微服務生態最佳解決方案。

3.Nacos 概念

Nacos 引入了一些基本的概念,系統性的瞭解一下這些概念可以幫助您更好的理解和正確的使用 Nacos 產品。

1.Namespace

Namespace 的設計就是用來進行資源隔離的,用於進行租戶粒度和多環境的配置隔離。不同的命名空間下,可以存在相同的 Group 或 Data ID 的配置。

從單個租戶的角度來看,我們要配置多套環境的配置,可以根據不同的環境來創建 Namespace,例如開發測試環境、測試環境、生產環境的資源等。命名方式一般是:項目名+環境,如mall-dev,可以在nacos的管理頁進行創建。

從多租戶的角度來看,每個租戶都可以有自己的命名空間。我們可以爲每個用戶創建一個命名空間,並給用戶分配對應的權限,每個租戶也可以有自己的多環境配置。

創建完成之後會生成一個唯一的UUID的字符串,這個字符串就可以在項目中nacos的地方配置使用。

2.Data ID
Data ID 通常用於組織劃分系統的配置集。一個系統或者應用可以包含多個配置集,每個配置集都可以被一個有意義的名稱標識。

在微服務中,每一個項目下有若干個服務,每個 DataID 是一個工程的主配置文件,類似於springboot項目中多application.properties的配置文件。

3.Group
通過一個有意義的字符串(如 Pay 或 Trade )對配置集進行分組,從而區分 Data ID 相同的配置集。當您在 Nacos 上創建一個配置時,如果未填寫配置分組的名稱,則配置分組的名稱默認採用 DEFAULT_GROUP 。

其實主要用來代表項目。如果只有單一的項目,沒必要麻煩,默認的即可。如果有多個項目用一個nacos環境,可以用項目作爲Group值來區分相同的配置文件。

Namespace(命名空間):用來隔離區分環境或租戶。
Data ID(配置集):用來區分多配置值,如redis、Mq、db等;
Group(分組):用來區分項目,將業務相關度比較高的放到一組裏面,例如訂單和支付。

4.自定義配置規範

1. Namespace: 默認public,命名規則:項目名爲開頭,如果有租戶區分則再拼接租戶標識, 最後是環境隔離,之間通過-分割,字母小寫。

規則:
${prefix}-${tenant}-${spring.profiles.active}

示例:

2. Group: 默認DEFAULT_GROUP,命名規則:以項目或業務名爲開頭,以GROUP結尾,通過_鏈接,字母大寫。

規則:
${prefix}_GROUP

示例:

3. DataId: 命名規則:通用的配置以common開頭,非通用的以項目名開頭,後續加以配置類別,最後以擴展名結尾,之間通過-鏈接,字母小寫。

規則:

  • 通用:common-${function}.${file-extension}
  • 非通用:${application-name}-${function}.${file-extension}

示例:

4. Nacos 註冊中心集成 springcloud

mven依賴:

<!--nacos 註冊中心-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

注意:版本 2.1.x.RELEASE 對應的是 Spring Boot 2.1.x 版本。版本 2.0.x.RELEASE 對應的是 Spring Boot 2.0.x 版本,版本 1.5.x.RELEASE 對應的是 Spring Boot 1.5.x 版本,更多版本對應關係參考:版本說明 Wiki

bootstrap.yaml

spring:
  application:
    name: service-a
  cloud:
    nacos:
      discovery:
        register-enabled: true
        server-addr: 172.30.13.74:8801,172.30.13.74:8802,172.30.13.74:8803
        namespace: 9faec1a8-3a76-4158-af81-963055755e2e

配置說明

| 配置項 |Key |默認值 |說明 |
| -------- | --------| -- |
| 服務端地址 |spring.cloud.nacos.discovery.server-addr|無|Nacos Server 啓動監聽的ip地址和端口|
|服務名|spring.cloud.nacos.discovery.service|${spring.application.name}|給當前的服務命名|
|服務分組|spring.cloud.nacos.discovery.group|DEFAULT_GROUP|設置服務所處的分組|
|服務分組|spring.cloud.nacos.discovery.namespace|public|設置服務所處的命名空間|
|是否集成Ribbon|ribbon.nacos.enabled|true|一般都設置成true即可|

開啓註冊功能

通過 Spring Cloud 原生註解 @EnableDiscoveryClient 開啓服務註冊發現功能

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

三、配置管理

Nacos除了可以作爲服務發現的註冊中心,還可以作爲配置中心。

1.springCloud 集成 Nacos

maven依賴:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>${latest.version}</version>
</dependency>

bootstrap.yaml

spring:
  application:
    name: cashier-user
  cloud:
    nacos:
      config:
        server-addr: 172.30.13.74:8845,172.30.13.74:8847,172.30.13.74:8849
#        prefix: cashier
        file-extension: yaml
        namespace: 9faec1a8-3a76-4158-af81-963055755e2e
        # 用於共享的配置文件
        shared-configs:
          - data-id: common-redis.yaml
            group: cashier-group
          - data-id: common-rocketmq.yaml
            group: cashier-group
          - data-id: common-mybatisplus.yaml
            group: cashier-group

配置說明

| 配置項 |Key |默認值 |說明 |
| --------| -------- | --- |
| 服務端地址 |spring.cloud.nacos.config.server-addr|無|Nacos Server 啓動監聽的ip地址和端口|
|服務名|spring.cloud.nacos.config.file-extension|無|配置文件擴展名|
|服務分組|spring.cloud.nacos.config.namespace|public|設置服務所處的命名空間|
|服務分組|spring.cloud.nacos.config.shared-configs|無|設置共享配置|

讀取規則

在Spring Cloud Nacos 中,Nacos是根據什麼規則找到對應配置文件的?
dataId 的完整格式如下:

${prefix}-${spring.profiles.active}.${file-extension}
  • prefix 默認爲 spring.application.name 的值,也可以通過配置項 spring.cloud.nacos.config.prefix來配置。
  • spring.profiles.active 即爲當前環境對應的 profile。 當 spring.profiles.active 爲空時,對應的連接符 - 也將不存在,dataId 的拼接格式變成 ${prefix}.${file-extension}
  • file-exetension 爲配置內容的數據格式,可以通過配置項 spring.cloud.nacos.config.file-extension 來配置。目前只支持 properties 和 yaml 類型。

假如 spring.application.name=nacos-demo, spring.profiles.active=devfile-extension=yaml,則配置優先級高到低順序爲:nacos-demo-dev.yaml -> nacos-demo.yaml -> nacos-demo

2. 加載多個配置

日常開發項目中經常會遇到多配置的場景,如application-redis.properties、application-mq.properties、application-db.properties、監控配置等等,而且有些配置文件有的各項目可以共享,有的是獨有的,那麼這些怎麼設置呢?

Nacos提供了共享配置(shared-configs)擴展配(extension-config),來解決這種問題。

每個配置中包含三個參數:data-id、group,refresh;前兩個不再贅述,refresh參數控制這個配置文件中的內容是否支持自動刷新,默認情況下,只有默認加載的配置纔會自動刷新,對於這些擴展的配置加載內容需要配置該設置時候纔會實現自動刷新。

如果沒有明確配置,默認情況下所有共享配置和擴展配置都不支持動態刷新。

共享配置(shared-configs)

Nacos在配置路徑spring.cloud.nacos.config.shared-configs下,允許我們指定⼀個或多個共享配置。

...
# 用於共享的配置文件
shared-configs:
  - data-id: common-redis.yaml
    group: cashier-group
    refresh: true
  - data-id: common-rocketmq.yaml
    group: cashier-group
    refresh: true
  - data-id: common-mybatisplus.yaml
    group: cashier-group
    refresh: true

擴展配(extension-config)

Nacos在配置路徑spring.cloud.nacos.config.extension-config下,允許我們指定⼀個或多個額外配置。

...
# 用於共享的配置文件
extension-configs:
  - data-id: actuator.yaml
    group: cashier-group
    # 讓擴展配置刷新
    refresh: true
  - data-id: log.yaml
    group: cashier-group
    refresh: true

關於優先級

配置文件既可以存在於本地項目中,也可以在Nacos中,那麼對於重複的配置項,優先級順序是怎樣的呢?

首先在默認情況下和本地配置相比,存在如下優先級:遠程配置 > 本地配置 > java代碼配置。當需要本地配置優先時,可以通過如下方式限制遠程配置的優先級。

spring:
  cloud:
    config:
      // 允許nacos被本地文件覆蓋
      allow-override: true
      // nacos不覆蓋任何本地文件
      override-none: true
      // nacos 覆蓋系統屬性。注意本地配置文件不是系統屬性
      override-system-properties: true

以上是本地配置和 Nacos 配置的優先級比較,而且需要在遠程配置中添加,否則不生效,通過上文的瞭解,我們在使用Nacos 配置的時候,Nacos 本身也主要有以下三類配置:

  1. 通過spring.cloud.nacos.config.shared-configs定義的共享配置。
  2. 通過spring.cloud.nacos.config.extension-configs定義的加載配置。
  3. 通過內部規則(spring.cloud.nacos.config.prefixspring.cloud.nacos.config.file-extensionspring.cloud.nacos.config.group 這幾個參數)拼接出來的配置。

當我們加載如上多個配置的時候,如果存在相同的 key 時,這些配置加載的優先級關係是怎麼樣的呢?

1、上述兩類配置都是數組,對同種配置,數組元素對應的下標越⼤,優先級越⾼。也就是排在後⾯的相同配置,將覆蓋排在前⾯的同名配置。

  • 同爲擴展配置,存在如下優先級關係:extension-configs[3] > extension-configs[2] > extension-configs[1] > extension-configs[0]。

  • 同爲共享配置,存在如下優先級關係:shared-configs[3] > shared-configs[2] > shared-configs[1] > shared-configs[0]。

2、不同種類配置之間,優先級按順序如下:主配置 > 擴展配置(extension-configs) > 共享配置(shared-configs)

讀取配置

在 nacos 中設置了屬性對應的配置值,如何在應用項目中讀取呢?

# 免驗籤的路徑
exclude-paths: /user/login,/login
# 驗籤開關
sign-switch: false
# 網關鏈接有效時間, 1000 * 60 * 60 * 24
link_expired_time: 86400000

其實讀取的方式很簡單,如果你的dataId設置的正確,直接通過spring的 @Value註解就可以獲取到對應的配置值。

@Value("${exclude-paths}")
private String excludePaths;

@Value("${sign-switch}")
private boolean signSwitch;

@Value("${link_expired_time}")
private Long linkExpiredTime;

關於動態刷新

我們使用Nacos主要是期望能通過它實現動態修改配置而不需要重啓服務,即配置熱更新,Nacos 通過 @RefreshScope註解來實現動態屬性值刷新,這是springcloud所屬的一個註解,通過註解可以知道,該註解作用於類和方法上。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {

	/**
	 * @see Scope#proxyMode()
	 * @return proxy mode
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

@RefreshScope@Value 必須一起出現,不然項目控制檯打印有變更日誌,但是請求結果卻一直沒有改變。

  • @RefreshScope 添加到類上,就是說明在項目運行過程中,如果遠程配置文件有做修改,修改的信息在@RefreshScope添加的類中有使用,就會將原有的實例註銷,在重新創建一個新的實例運行。這樣就能保證在項目不重啓的情況下讀取到最新的修改信息。
  • 如果修改的配置信息在沒有添加@RefreshScope的類中使用,這個類的實例就不會註銷,所以不管怎麼修改,沒有加@RefreshScope的類請求結果一直都會是項目運行時加載的舊數據。

這種用法是最簡單的,也符合我們常用的 spring 開發習慣,但是它有需要注意的點,使用不當會造成讀取不到動態更新的配置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章