一文詳解 Nacos 高可用特性


簡介: 我今天介紹的 Nacos 高可用,是 Nacos 為了提升系統穩定性而采取的一系列手段。Nacos 的高可用不僅僅存在於服務端,同時也存在於客戶端,以及一些與可用性相關的功能特性中,這些點組裝起來,共同構成了 Nacos 的高可用。

前言

服務注冊發現是一個經久不衰的話題,Dubbo 早期開源時默認的注冊中心 ZooKeeper 最早進入人們的視線,並且在很長一段時間里,人們將注冊中心和 ZooKeeper 划上了等號,可能 ZooKeeper 的設計者都沒有想到這款產品對微服務領域造成了如此深厚的影響,直到 Spring Cloud 開始流行,其自帶的 Eureka 進入了人們的視野,人們這才意識到原來注冊中心還可以有其他的選擇。再到后來,熱衷於開源的阿里把目光也聚焦在了注冊中心這個領域, Nacos 橫空出世。

 

image.png

Kirito 在做注冊中心選型時的思考:曾經我沒得選,現在我只想選擇一個好的注冊中心,它最好是開源的,這樣開放透明,有自我的掌控力。不僅要開源,它還要有活躍的社區,以確保特性演進能夠滿足日益增長的業務需求,出現問題也能即使修復,功能還要很強大。除了滿足注冊服務、推送服務外,還要有完善的微服務體系中所需的功能。最重要的,它還要穩定,最好有大廠的實際使用場景背書,證明這是一個經得起實戰考驗的產品。當然,雲原生特性,安全特性也是很重要的······

似乎 Kirito 對注冊中心的要求實在是太高了,但這些五花八門的注冊中心呈現在用戶眼前,總是免不了一番比較。正如上面所言,功能特性、成熟度、可用性、用戶體驗度、雲原生特性、安全都是可以拿出來做比較的話題。今天這篇文章重點介紹的是 Nacos 在可用性上的體現,希望借助於這篇文章,能夠讓你對 Nacos 有一個更加深刻的認識。

高可用介紹

當我們在聊高可用時,我們在聊什么?

  • 系統可用性達到 99.99%
  • 在分布式系統中,部分節點宕機,依舊不影響系統整體運行
  • 服務端集群化部署多個節點

這些都可以認為是高可用,而我今天介紹的 Nacos 高可用,則是 Nacos 為了提升系統穩定性而采取的一系列手段。Nacos 的高可用不僅僅存在於服務端,同時也存在於客戶端,以及一些與可用性相關的功能特性中,這些點組裝起來,共同構成了 Nacos 的高可用。

客戶端重試

先統一一下語義,在微服務架構中一般會有三個角色:Consumer、Provider 和 Registry,在今天注冊中心的主題中,Registry 是 nacos-server,而 Consumer 和 Provider 都是 nacos-client。

在生產環境,我們往往需要搭建 Nacos 集群,在 Dubbo 也需要顯式地配置上集群地址:

<dubbo:registry protocol="nacos" address="192.168.0.1:8848,192.168.0.2:8848,192.168.0.3:8848"/>

當其中一台機器宕機時,為了不影響整體運行,客戶端會存在重試機制。

 

image.png

邏輯非常簡單,拿到地址列表,在請求成功之前逐個嘗試,直到成功為止。

該可用性保證存在於 nacos-client 端。

一致性協議 distro

首先給各位讀者打個強心劑,不用看到”一致性協議“這幾個字就被勸退,本節不會探討一致性協議的實現過程,而是重點介紹其與高可用相關的特性。有的文章介紹 Nacos 的一致性模型是 AP + CP,這么說很容易讓人誤解,其實 Nacos 並不是支持兩種一致性模型,也並不是支持兩種模型的切換,介紹一致性模型之前,需要先了解到 Nacos 中的兩個概念:臨時服務和持久化服務。

  • 臨時服務(Ephemeral):臨時服務健康檢查失敗后會從列表中刪除,常用於服務注冊發現場景。
  • 持久化服務(Persistent):持久化服務健康檢查失敗后會被標記成不健康,常用於 DNS 場景。

臨時服務使用的是 Nacos 為服務注冊發現場景定制化的私有協議 distro,其一致性模型是 AP;而持久化服務使用的是 raft 協議,其一致性模型是 CP。所以以后不要再說 Nacos 是 AP + CP 了,更建議加上服務節點狀態或者使用場景的約束。

distro 協議與高可用有什么關系呢?上一節我們提到 nacos-server 節點宕機后,客戶端會重試,但少了一個前提,即 nacos-server 少了一個節點后依舊可以正常工作。Nacos 這種有狀態的應用和一般無狀態的 Web 應用不同,並不是說只要存活一個節點就可以對外提供服務的,需要分 case 討論,這與其一致性協議的設計有關。distro 協議的工作流程如下:

  • Nacos 啟動時首先從其他遠程節點同步全部數據。
  • Nacos 每個節點是平等的都可以處理寫入請求,同時把新數據同步到其他節點。
  • 每個節點只負責部分數據,定時發送自己負責數據的校驗值到其他節點來保持數據一致性。

 

image.png

如上圖所示,每個節點負責一部分服務的寫入,但每個節點都可以接收到寫入請求,這時就存在兩種情況:

  • 當該節點接收到屬於該節點負責的服務時,直接寫入。
  • 當該節點接收到不屬於該節點負責的服務時,將在集群內部路由,轉發給對應的節點,從而完成寫入。

讀取操作則不需要路由,因為集群中的各個節點會同步服務狀態,每個節點都會有一份最新的服務數據。

而當節點發生宕機后,原本該節點負責的一部分服務的寫入任務會轉移到其他節點,從而保證 Nacos 集群整體的可用性。

image.png

一個比較復雜的情況是,節點沒有宕機,但是出現了網絡分區,即下圖所示:

image.png

這個情況會損害可用性,客戶端會表現為有時候服務存在有時候服務不存在。

綜上,Nacos 的 distro 一致性協議可以保證在大多數情況下,集群中的機器宕機后依舊不損害整體的可用性。該可用性保證存在於 nacos-server 端。

本地緩存文件 Failover 機制

注冊中心發生故障最壞的一個情況是整個 Server 端宕機,這時候 Nacos 依舊有高可用機制做兜底。

一道經典的 Dubbo 面試題:當 Dubbo 應用運行時,Nacos 注冊中心宕機,會不會影響 RPC 調用。這個題目大多數應該都能回答出來,因為 Dubbo 內存里面是存了一份地址的,一方面這樣的設計是為了性能,因為不可能每次 RPC 調用時都讀取一次注冊中心,另一面,注冊中心宕機后內存會有一份數據,這也起到了可用性的保障(盡管可能 Dubbo 設計者並沒有考慮這個因素)。

那如果,我在此基礎上再拋出一個問題:Nacos 注冊中心宕機,Dubbo 應用發生重啟,會不會影響 RPC 調用。如果了解了 Nacos 的 Failover 機制,應當得到和上一題同樣的回答:不會。

Nacos 存在本地文件緩存機制,nacos-client 在接收到 nacos-server 的服務推送之后,會在內存中保存一份,隨后會落盤存儲一份快照。snapshot 默認的存儲路徑為:{USER_HOME}/nacos/naming/ 中:

 

image.png

這份文件有兩種價值,一是用來排查服務端是否正常推送了服務;二是當客戶端加載服務時,如果無法從服務端拉取到數據,會默認從本地文件中加載。

前提是構建 NacosNaming 時傳入了該參數:namingLoadCacheAtStart=true 
Dubbo 2.7.4 及以上版本支持該 Nacos 參數;開啟該參數的方式:dubbo.registry.address=nacos://127.0.0.1:8848?namingLoadCacheAtStart=true

在生產環境,推薦開啟該參數,以避免注冊中心宕機后,導致服務不可用,在服務注冊發現場景,可用性和一致性 trade off 時,我們大多數時候會優先考慮可用性。

細心的讀者還注意到 
{USER_HOME}/nacos/naming/{namespace} 下除了緩存文件之外還有一個 failover 文件夾,里面存放着和 snapshot 一致的文件夾。這是 Nacos 的另一個 failover 機制,snapshot 是按照某個歷史時刻的服務快照恢復恢復,而 failover 中的服務可以人為修改,以應對一些極端場景。

該可用性保證存在於 nacos-client 端。

心跳同步服務

心跳機制一般廣泛存在於分布式通信領域,用於確認存活狀態。一般心跳請求和普通請求的設計是有差異的,心跳請求一般被設計的足夠精簡,這樣在定時探測時可以盡可能避免性能下降。而在 Nacos 中,出於可用性的考慮,一個心跳報文包含了全部的服務信息,這樣相比僅僅發送探測信息降低了吞吐量,而提升了可用性,怎么理解呢?考慮以下的兩種場景:

  • nacos-server 節點全部宕機,服務數據全部丟失。nacos-server 即使恢復運作,也無法恢復出服務,而心跳包含全部內容可以在心跳期間就恢復出服務,保證可用性。
  • nacos-server 出現網絡分區。由於心跳可以創建服務,從而在極端網絡故障下,依舊保證基礎的可用性。

以下是對心跳同步服務的測試,使用阿里雲 MSE 提供 Nacos 集群進行測試:

 

image.png

調用 OpenApi 依次刪除各個服務:

curl -X "DELETE mse-xxx-p.nacos-ans.mse.aliyuncs.com:8848/nacos/v1/ns/service?serviceName=providers:com.alibaba.edas.boot.EchoService:1.0.0:DUBBO&groupName=DEFAULT_GROUP"

 

image.png

過 5s 后刷新,服務又再次被注冊了上來,符合我們對心跳注冊服務的預期。

集群部署模式高可用

最后給大家分享的 Nacos 高可用特性來自於其部署架構。

節點數量

我們知道在生產集群中肯定不能以單機模式運行 Nacos,那么第一個問題便是:我應該部署幾台機器?前面我們提到 Nacos 有兩個一致性協議:distro 和 raft,distro 協議不會有腦裂問題,所以理論來說,節點數大於等於 2 即可;raft 協議的投票選舉機制則建議是 2n+1 個節點。綜合來看,選擇 3 個節點是起碼的,其次處於吞吐量和更高可用性的考量,可以選擇 5 個,7 個,甚至 9 個節點的集群。

多可用區部署

組成集群的 Nacos 節點,應該盡可能考慮兩個因素:

  • 各個節點之間的網絡時延不能很高,否則會影響數據同步。
  • 各個節點所處機房、可用區應當盡可能分散,以避免單點故障。

以阿里雲的 ECS 為例,選擇同一個 Region 的不同可用區就是一個很好的實踐。

部署模式

主要分為 K8s 部署和 ECS 部署兩種模式。

ECS 部署的優點在於簡單,購買三台機器即可搭建集群,如果你熟練 Nacos 集群部署的話,這不是難事,但無法解決運維問題,如果 Nacos 某個節點出現 OOM 或者磁盤問題,很難迅速摘除,無法實現自運維。

K8s 部署的有點在於雲原生運維能力強,可以在節點宕機后實現自恢復,保障 Nacos 的平穩運行。前面提到過,Nacos 和無狀態的 Web 應用不同,它是一個有狀態的應用,所以在 K8s 中部署,往往要借助於 StatefulSet 和 Operator 等組件才能實現 Nacos 集群的部署和運維。

MSE Nacos 的高可用最佳實踐

阿里雲微服務引擎 MSE 提供了 Nacos 集群的托管能力,實現了集群部署模式的高可用。

  • 當創建多個節點的集群時,系統會默認分配在不同可用區。同時,這對於用戶來說又是透明的,用戶只需要關心 Nacos 的功能即可,MSE 替用戶兜底可用性。
  • MSE 底層使用 K8s 運維模式部署 Nacos。歷史上出現過用戶誤用 Nacos 導致部分節點宕機的問題,但借助於 K8s 的自運維模式,宕機節點迅速被拉起,以至於用戶可能都沒有意識到自己發生宕機。

下面模擬一個節點宕機的場景,來看看 K8s 如何實現自恢復。

一個三節點的 Nacos 集群:

 

image.png

執行kubectl delete pod mse-7654c960-1605278296312-reg-center-0-2 以模擬部分節點宕機的場景。

 

image.png

大概 2 分鍾后,節點恢復,並且角色發生了轉換,Leader 從殺死的 2 號節點轉給 1 號節點。

 

image.png

總結

本文從多個角度出發,總結了一下 Nacos 是如何保障高可用的。高可用特性絕不是靠服務端多部署幾個節點就可以獲得的,而是要結合客戶端使用方式、服務端部署模式、使用場景綜合來考慮的一件事。

特別是在服務注冊發現場景,Nacos 為可用性做了非常多的努力,而這些保障,ZooKeeper 是不一定有的。在做注冊中心選型時,可用性保障上,Nacos 絕對是優秀的。

 

原文鏈接

本文為阿里雲原創內容,未經允許不得轉載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM