SpringCloudAlibaba註冊中心與配置中心之利器Nacos實戰與源碼分析(下)
源碼資料
文檔資料
<<Nacos架構與原理>>書籍於2021.12.21發布,並在Nacos官方網站非常Nice的提供其電子書的下載。我們學習Nacos源碼更多是要吸取其優秀的設計理念和思想,這個和我們學習其他開源項目的初衷是一致的。
Nacos架構與原理 //developer.aliyun.com/topic/download?id=8230
微服務治理技術白皮書 //developer.aliyun.com/ebook/download/7565?spm=a2c6h.26392459.ebook-detail.3.12d959e7lHLVZ8
關於源碼分析如果有時間還可以看早之前譚峰寫的<<Spring Cloud Alibaba微服務原理與實戰>>
Nacos讀音為/nɑ:kəʊs/ ,是 Dynamic Naming and Configuration Service 的首字母簡稱;⼀個更易於構建雲原生應用的動態服務發現、配置管理和服務管理平台。 Nacos來源阿里內部三個項目( Configserver/Diamond/ Vipserver 內核)的合體。主要優勢為易用、穩定、實時、規模。
阿里微服務 DNS(Dubbo+Nacos+Spring-cloud-alibaba/Seata/ Sentinel)最佳實踐集性能和應用一體,是目前 Java 微服務生態最佳解決方案。
下載源碼
Nacos GitHub源碼 //github.com/alibaba/nacos/releases 最新版本為2.1.0 (Apr 29, 2022),而1系列最新版本為1.4.3
源碼啟動
導入Idea後執行mvn compile,等待項目編譯,編譯完成資訊如下

打開Nacos的Main類,可以看到是一個SpringBoot程式,nacos-console控制台項目配置啟動的參數如下
-Dnacos.standalone=true -Dnacos.home=C:\\nacos

啟動Nacos,一個本地內嵌資料庫模式就成功啟動了

訪問//localhost:8848/nacos ,輸入用戶和密碼nacos/nacos進入控制台主頁面

總體設計
設計原則
- 極簡原則,簡單才好用,簡單才穩定,簡單才易協作。
- 架構⼀致性,⼀套架構要能適應開源、內部、商業化(公有雲及專有雲)3 個場景。
- 擴展性,以開源為內核,商業化做基礎,充分擴展,方便用戶擴展。
- 模組化,將通用部分抽象下沉,提升程式碼復用和健壯性。
- 長期主義,不是要⼀個能支撐未來 3 年的架構,而是要能夠支撐 10 年的架構。
- 開放性,設計和討論保持社區互動和透明,方便大家協作。
分層架構
整體架構分為用戶層、業務層、內核層和插件,用戶層主要解決用戶使用的易用性問題,業務層主要解決服務發現和配置管理的功能問題,內核層解決分散式系統⼀致性、存儲、高可用等核心問題, 插件解決擴展性問題。
配置模型
基礎模型
- Nacos 提供可視化的控制台,可以對配置進行發布、更新、刪除、灰度、版本管理等功能。
- SDK 可以提供發布配置、更新配置、監聽配置等功能。
- SDK 通過 GRPC 長連接監聽配置變更,Server 端對比 Client 端配置的 MD5 和本地 MD5 是否相等,不相等推送配置變更。
- SDK 會保存配置的快照,當服務端出現問題的時候從本地獲取。

配置資源模型
Namespace 的設計就是用來進行資源隔離的,我們在進行配置資源的時候可以從以下兩個角度來 看:
- 從單個租戶的角度來看,我們要配置多套環境的配置,可以根據不同的環境來創建 Namespace。
- 從多個租戶的角度來看,每個租戶都可以有自己的命名空間。
配置存儲模型
- config_info 存儲配置資訊的主表,裡面包含 dataId、groupId、content、tenantId、encryptedDataKey 等數據。
- config_info_beta 灰度測試的配置資訊表,存儲的內容和 config_info 基本相似。有⼀個 beta_ips 欄位用於客戶端請求配置時判斷是否是灰度的 ip。
- config_tags_relation 配置的標籤表,在發布配置的時候如果指定了標籤,那麼會把標籤和配置的關聯資訊存儲在該表中。
- his_config_info 配置的歷史資訊表,在配置的發布、更新、刪除等操作都會記錄⼀條數據,可以做多版本管理和快速回滾。
內核設計
Nacos一致性協議
Nacos在集群模式下,需要考慮如何保障各個節點之間 的數據⼀致性以及數據同步,而要解決這個問題,就不得不引入共識演算法,通過演算法來保障各個節點之間的數據的⼀致性。基於Nacos 是⼀個集服務註冊發現以及配置管理於⼀體的組件場景觸發,因此對於集群下各個節點之間的數據⼀致性保障問題,需要拆分成兩個方面:
- 從服務註冊發現來看
- 服務發現註冊中心,在當前微服務體系下,是十分重要的組件,服務之間感知對方服務的當前可正常提供服務的實例資訊,必須從服務發現註冊中心進行獲取,因此對於服務註冊發現中心組件的可用性,提出了很高的要求,需要在任何場景下,盡最大可能保證服務註冊發現能力可以對外提供服務;同時 Nacos 的服務註冊發現設計,採取了心跳可自動完成服務數據補償的機制。如果數據丟 失的話,是可以通過該機制快速彌補數據丟失。
- 因此,為了滿足服務發現註冊中心的可用性,強⼀致性的共識演算法這裡就不太合適了,因為強⼀致性共識演算法能否對外提供服務是有要求的,如果當前集群可用的節點數沒有過半的話,整個演算法直 接「罷工」,而最終⼀致共識演算法的話,更多保障服務的可用性,並且能夠保證在⼀定的時間內各 個節點之間的數據能夠達成⼀致。
- 上述的都是針對於 Nacos 服務發現註冊中的非持久化服務而言(即需要客戶端上報心跳進行服務實例續約)。而對於 Nacos 服務發現註冊中的持久化服務,因為所有的數據都是直接使用調用 Nacos 服務端直接創建,因此需要由 Nacos 保障數據在各個節點之間的強⼀致性,故而針對此類型的服務數據,選擇了強⼀致性共識演算法來保障數據的⼀致性。
- 從配置管理來看
- 配置數據,是直接在 Nacos 服務端進行創建並進行管理的,必須保證大部分的節點都保存了此配置數據才能認為配置被成功保存了,否則就會丟失配置的變更,如果出現這種情況,問題是很嚴重的,如果是發布重要配置變更出現了丟失變更動作的情況,那多半就要引起嚴重的現網故障了,因此對於配置數據的管理,是必須要求集群中大部分的節點是強⼀致的,而這裡的話只能使用強⼀致性共識演算法。
- Nacos一致性協議演算法選擇
- 強⼀致性共識演算法:當前工業生產中,最多使用的就是 Raft 協議,Raft 協議更容易讓人理解, 並且有很多成熟的工業演算法實現,比如螞蟻金服的 JRaft、Zookeeper 的 ZAB、Consul 的 Raft、 百度的 braft、Apache Ratis,Nacos選擇了支援多 RaftGroup的 JRaft,為 Nacos 後面的多數據分片帶來了可能。
- 最終⼀致性協議:Distro 協議是阿里巴巴自研的⼀個最終⼀致性協議,而最終⼀致性協議有很多,比如 Gossip、 Eureka 內的數據同步演算法。而 Distro 演算法是集 Gossip 以及 Eureka 協議的優點並加以優化而出來的。

Nacos⼀致性協議最最基礎的寫動作和讀動作兩個方法如下

任何使用⼀致性協議的,都只需要使用 getData 以及 write 方法即可。Nacos 對於 AP、CP 的⼀致性協議介面使用抽象都在 consistency 包,並且在實現具體的⼀致性協議時,採用了插件可插拔的形式,進⼀步將⼀致性協議具體實現邏輯和服務註冊發現、配置管理兩個模組達到解耦的目的。
此外nacos還通過數據存儲抽象來統一有數據存儲層管理保障數據存儲以及多節點⼀致性。如KvStorage介面

存儲層進⼀步實現插件化的設計,也實現 Nacos 的計算層與存儲層徹底分離。
Nacos自研的Distro協議
Distro 協議是 Nacos 社區自研的⼀種 AP 分散式協議,是面向臨時實例設計的⼀種分散式協議, 其保證了在某些 Nacos 節點宕機後,整個臨時實例處理系統依舊可以正常工作。作為⼀種有狀態的中間件應用的內嵌協議,Distro 保證了各個 Nacos 節點對於海量註冊請求的統⼀協調和存儲。Distro的設計思想
- Nacos 每個節點是平等的都可以處理寫請求,同時把新數據同步到其他節點。
- 每個節點只負責部分數據,定時發送自己負責數據的校驗值到其他節點來保持數據⼀致性。
- 每個節點獨立處理讀請求,及時從本地發出響應。
Distro 協議是 Nacos 對於臨時實例數據開發的⼀致性協議。其數據存儲在快取中,並且會在啟動時進行全量數據同步,並定期進行數據校驗。
在 Distro 協議的設計思想下,每個 Distro 節點都可以接收到讀寫請求。所有的 Distro 協議的請求場景主要分為三種情況:
- 當該節點接收到屬於該節點負責的實例的寫請求時,直接寫入。
- 當該節點接收到不屬於該節點負責的實例的寫請求時,將在集群內部路由,轉發給對應的節點, 從而完成讀寫。
- 當該節點接收到任何讀請求時,都直接在本機查詢並返回(因為所有實例都被同步到了每台機 器上)。
Distro 協議作為 Nacos 的內嵌臨時實例⼀致性協議,保證了在分散式環境下每個節點上面的服務資訊的狀態都能夠及時地通知其他節點,可以維持數十萬量級服務實例的存儲和⼀致性。
Nacos定址機制
Nacos 支援單機部署以及集群部署,針對單機模式,Nacos 只是自己和自己通訊;對於集群模式, 則集群內的每個 Nacos 成員都需要相互通訊。無論是單機模式,還是集群模式,其根本區別只是 Nacos 成員節點的個數是單個還是多個,並且, 要能夠感知到節點的變更情況:節點是增加了還是減少了;當前最新的成員列表資訊是什麼;以何 種方式去管理成員列表資訊;如何快速的支援新的、更優秀的成員列表管理模式等等。 因此抽象出了⼀個 MemberLookup 介面

- 單機定址:找到自己的 IP:PORT 組合資訊,然後格式化為⼀個節點資訊, 調用 afterLookup 然後將資訊存儲到 ServerMemberManager 中。

- 文件定址:是 Nacos 集群模式下的默認定址實現。文件定址模式很簡單,其實就是每個 Nacos節點需要維護⼀個叫做 cluster.conf 的文件。該文件默認只需要填寫每個成員節點的 IP 資訊即可,埠會自動選擇 Nacos 的默認埠 8848, 如過說有特殊需求更改了 Nacos 的埠資訊,則需要在該文件將該節點的完整網路地址資訊補充 完整(IP:PORT)。 當 Nacos 節點啟動時,會讀取該文件的內容,然後將文件內的 IP 解析為節點列表,調用 afterLookup 存入 ServerMemberManager。如果發現集群擴縮容,那麼就需要修改每個 Nacos 節點下的 cluster.conf 文件,然後 Nacos 內部的文件變動監聽中心會自動發現文件修改,重新讀取文件內容、載入 IP 列表資訊、更新新增的節點。

-
地址伺服器定址:地址伺服器定址模式是 Nacos 官方推薦的⼀種集群成員節點資訊管理,該模式利用了⼀個簡易的web 伺服器,用於管理 cluster.conf 文件的內容資訊,這樣,運維人員只需要管理這⼀份集群成員節點內容即可,而每個 Nacos 成員節點,只需要向這個 web 節點定時請求當前最新的集群成員節
點列表資訊即可。通過地址伺服器這種模式,大大簡化了 Nacos 集群節點管理的成本,同時,地址伺服器是⼀個非常簡單的 web 程式,其程式的穩定性能夠得到很好的保障。


Nacos服務發現模組
設計原理
數據模型
Nacos 在經過內部多年生產經驗後提煉出的數據模型,則是⼀種服務-集群-實例的三層模型;Nacos 提供了四層的數據邏輯隔離模型,用戶帳號對應的可能是⼀個企業或者獨立的個體,⼀個用戶帳號可以新建多個命名空間。
臨時實例和持久化實例
定義上區分臨時實例和持久化實例的關鍵是健康檢查的方式,臨時實例使用客戶端上報模式,而持久化實例使用服務端反向探測模式。⼀些基礎的組件例如資料庫、快取等,這些往往 不能上報心跳,這種類型的服務在註冊時,就需要作為持久化實例註冊。而上層的業務服務,例如微服務或者 Dubbo 服務,服務的 Provider 端支援添加彙報心跳的邏輯,此時就可以使用動態服 務的註冊方式。
數據⼀致性
⼀致性的選型目前來看基本可以歸為兩家:⼀種是基於 Leader 的非對等部署的單點寫⼀致性,⼀種是對等部署的多寫⼀致性。
- 當註冊的服務節點不會 定時發送心跳到註冊中心時,強⼀致協議看起來是唯⼀的選擇,因為無法通過心跳來進行數據的補償註冊,第⼀次註冊就必須保證數據不會丟失。
- 而當客戶端會定時發送心跳來彙報健康狀態時,第⼀次的註冊的成功率並不是非常關鍵(當然也很關鍵,只是相對來說我們容忍數據的少量寫失敗), 因為後續還可以通過心跳再把數據補償上來。
Nacos 因為要支援多種服務類型的註冊,並能夠具有機房容災、集群擴展等必不可少的能力,在1.0.0 正式支援 AP 和 CP 兩種⼀致性協議並存。⼀致性協議實現,⼀個是基於簡化的 Raft 的 CP ⼀致性(基於 Leader 進行寫入,其 CP 也並不是嚴格的,只是能保證⼀半所見⼀致,以及數據的丟失概率較小),⼀個是基於自研協議 Distro 的 AP ⼀致性。
健康檢查
Nacos 目前支援臨時實例使用心跳上報方式維持活性,發送心跳的周期默認是 5 秒,Nacos 服務端會在 15 秒沒收到心跳後將實例設置為不健康,在 30 秒沒收到心跳時將這個臨時實例摘除。客戶端健康檢查主要關注客戶端上報心跳的方式、服務端摘除不健康客戶端的機制。而服務端健康檢查,則關注探測客戶端的方式、靈敏度及設置客戶端健康狀態的機制。Nacos 既支援客戶端的健康檢查,也支援服務端的健康檢查,同⼀個服務可以切換健康檢查模式。
性能與容量
影響讀寫性能的因素很多:⼀致性協議、機器的配置、集群的規模、存量數據的規模、數據結構及讀寫邏輯的設計等等。
服務數據模型
-
定義服務
- 命名空間(Namespace):Nacos 數據模型中最頂層、也是包含範圍最廣的概念,用於在類似環境或租戶等需要強制隔離的場景中定義。Nacos 的服務也需要使用命名空間來進行隔離。
- 分組(Group):Nacos 數據模型中次於命名空間的⼀種隔離概念,區別於命名空間的強制隔離屬性,分組屬於⼀個弱隔離概念,主要用於邏輯區分⼀些服務使用場景或不同應用的同名服務, 最常用的情況主要是同⼀個服務的測試分組和生產分組、或者將應用名作為分組以防止不同應用提供的服務重名。
- 服務名(Name):該服務實際的名字,⼀般用於描述該服務提供了某種功能或能力。
-
服務元數據
- 進⼀步定義了 Nacos 中服務的細節屬性和描述資訊,包括健康保護閾值、實例選擇器(Selector)、 拓展數據(extendData)。
-
實例
- 網路 IP 地址:該實例的 IP 地址,在 Nacos2.0 版本後支援設置為域名。
- 網路埠:該實例的埠資訊。
- 健康狀態(Healthy):用於表示該實例是否為健康狀態。
- 集群(Cluster):用於標示該實例歸屬於哪個邏輯集群。
- 拓展數據(extendData):用於用戶自定義擴展的元數據內容,形式為 K-V。可以在實例中拓展該實例的元數據資訊,方便用戶實現自己的自定義邏輯和標示該實例。
-
實例元數據:權重、上線狀態、拓展數據。
⽣命周期
- 服務的⽣命周期
- 直接創建服務
- 註冊實例時自動創建服務
- 實例的生命周期
- 實例的生命周期開始於註冊實例的請求。
- 持久化的實例會通過健康檢查的狀態維護健康狀態,但是不會自動的終止該實例的生命周期。
- 而非持久化的實例,會根據版本的不同,採用不同的方式維持健康狀態。
健康檢查
- 第⼀種方式是客戶端主動上報,告訴服務端自己健康狀態,如果在⼀段時間沒有上報,那麼我們就認為服務已經不健康。對於健康檢查機制主要都採用了 TTL(Time To Live)機制,即客戶端在 ⼀定時間沒有向註冊中心發送心跳,那麼註冊中心會認為此服務不健康,進而觸發後續的剔除邏輯。
- 第二種,則是服務端主動向客戶端進行探測,檢查客戶端是否還被能探測到。

-
臨時實例健康檢查機制:在 Nacos 中,用戶可以通過兩種方式進行臨時實例的註冊,通過 Nacos 的 OpenAPI 進行服務註冊或通過 Nacos 提供的 SDK 進行服務註冊。
- OpenAPI 的註冊方式實際是用戶根據自身需求調用 Http 介面對服務進行註冊,然後通過 Http 介面發送心跳到註冊中心。在註冊服務的同時會註冊⼀個全局的客戶端心跳檢測的任務。在服務⼀段時間沒有收到來自客戶端的心跳後,該任務會將其標記為不健康,如果在間隔的時間內還未收到心跳,那麼該任務會將其剔除。
- SDK 的註冊方式實際是通過 RPC 與註冊中心保持連接(Nacos 2.x 版本中,舊版的還是仍然通過OpenAPI 的方式),客戶端會定時的通過 RPC 連接向 Nacos 註冊中心發送心跳,保持連接的存活。如果客戶端和註冊中心的連接斷開,那麼註冊中心會主動剔除該 client 所註冊的服務,達到下線的效果。同時 Nacos 註冊中心還會在註冊中心啟動時,註冊⼀個過期客戶端清除的定時任務,用於刪除那些健康狀態超過⼀段時間的客戶端。

-
永久實例健康檢查機制:永久實例的的健康檢查,Nacos 採用的是註冊中心探測機制,註冊中心會在永久服務初始化時根據客戶端選擇的協議類型註冊探活的定時任務。Nacos 現在內置提供了三種探測的協議,即Http、TCP 以及 MySQL 。

Nacos配置管理模組
配置一致性模型
Nacos 配置管理⼀致性協議包括 Server 間⼀致性協議和 SDK 與Server 的⼀致性協議,配置作為分散式系統中非強⼀致數據,在出現腦裂的時候可用性高於⼀致性, 因此阿里配置中心是採用 AP ⼀致性協議。
- Server 間的⼀致性協議
- 無 DB 模式:Server 間採用 Raft 協議保證數據⼀致性。
- 有 DB 模式(讀寫分離架構):⼀致性的核心是 Server 與 DB 保持數據⼀致性,從而保證 Server 數據⼀致;Server 之間都是對等的。數據寫任何⼀個 Server,優先持久化,持久化成功後非同步通知其他節點到資料庫中拉取最新配置值,並且通知寫入成功。

- SDK 與 Server 的⼀致性協議
- SDK 與 Server ⼀致性協議的核心是通過 MD5 值是否⼀致,如果不⼀致就拉取最新值。
- Nacos 1.X 採用 Http 1.1 短鏈接模擬長鏈接,每 30s 發⼀個心跳跟 Server 對比 SDK 配置 MD5 值是否跟 Server 保持⼀致,如果⼀致就 hold 住鏈接,如果有不⼀致配置,就把不⼀致的配置返回,然後 SDK 獲取最新配置值。
- Nacos 2.x 相比上面 30s ⼀次的長輪訓,升級成長鏈接模式,配置變更,啟動建立長鏈接,配置變更服務端推送變更配置列表,然後 SDK 拉取配置更新,因此通訊效率大幅提升。
- SDK 與 Server ⼀致性協議的核心是通過 MD5 值是否⼀致,如果不⼀致就拉取最新值。
客戶端的長輪詢是通過反射來完成NacosConfigService的實例化

客戶端長輪詢也是一個執行緒,啟動定時任務

Nacos高可用
- 同城容災
- Nacos 本身是採用 AP 的⼀致性模式,同 Region 多個可用區部署,任何⼀個可用區出問題,剩下部分繼續工作。
- 數據多級容災
- Nacos 持久化存儲做了主備容災,而且底層存儲數據多副本高可用保障。
- Nacos Server 有全量快取數據,即使存儲掛或者不可用,隻影響寫,核心的讀服務不受影響。
- Nacos SDK 有所需服務和配置快取,Server 即使全掛,走本地快取,保證核心業務調用不受影響。
**本人部落格網站 **IT小神 www.itxiaoshen.com

