Nacos 簡介
Nacos 在阿里巴巴起源於 2008 年五彩石項目,該項目完成了微服務拆分和業務中台建設,隨着雲計算和開源環境的興起,2018 年我們深刻感受到開源軟件行業的影響,因此決定將 Nacos 開源,輸出阿里十年關於服務發現和配管管理的沉淀,推動微服務行業發展,加速企業數字化轉型。
目前 Nacos 支持主流微服務開發語言 & 主流服務框架和配置管理框架,比如支持 Duboo 和 SCA, 還對接了一些雲原生的組件比如 coreDNS 和 sentinel 等。
客戶端語言方面支持諸如 Java、go python 等主流語言,還有近期剛發布正式版本的 C# 和 C++,在此感謝所有社區貢獻者的支持。
Nacos 開源 2 年多以來,共發布了 34 個版本,其中有一些比較重要的里程碑版本;Nacos 還非常年輕,有很大的進步空間,歡迎社區及各界大佬一起共同建設。
Nacos 1.X 架構及問題
接下來我們看一下 nacos1.x 架構及其分析一下存在的比較重要的問題。首先來看一下架構簡圖。
Nacos 1.X 架構層次
Nacos 1.X 大致分為 5 層, http://www.jintianxuesha.com/?cate=2 分別是接入、通信、功能、同步和持久化。
接入層是用戶最直接交互的層面,主要有 Nacos 客戶端,以及依賴客戶端的 Dubbo 和 SCA 以及用戶操作的控制台 Console 組成。客戶端和 Console 進行服務和配置操作,統一通過 HTTP 的 OpenAPI 發起通信請求。
通信層主要基於 HTTP 的短連接請求模型進行,部分推送功能通過 UDP 進行通信。
功能目前有服務發現和配置管理,這層也就是實際管理服務和配置的業務層。
同步層有數據同步的 AP 模式 Distro 和 CP 模式 Raft,還有有一個最簡易的水平通知 Notify,用處各不相同:
- Distro:非持久化服務的同步模式。
- Raft:持久化服務的同步模式、以及使用 Derby 作為配置的存儲時同步配置操作。
- Notify:使用 MySQL 作為配置的存儲時,通知其他節點更新緩存及發起配置推送。
持久化層 Nacos 使用 MySQL、Derby 和本地文件系統來進行數據的持久化 配置信息,用戶信息,權限信息存儲在 MySQL 或 Derby 數據庫中, 持久化服務信息及服務和實例元數據信息存儲在本地文件系統。
Nacos 1.X 架構下的服務模型
我們通過一個服務發現的流程,再深入熟悉一下 Nacos 1.X 架構和基於當前架構的 Nacos 服務發現模型。
Nacos 客戶端注冊服務會通過 OpenAPI 發送 Http 注冊服務的請求,請求內容會帶上服務信息及實例信息,通常這個步驟是由微服務框架 SCA 和 dubbo 完成。
服務端收到請求后,會先在 Contoller 中進行數據的讀取和校驗,比如 IP 是否合法,服務名是否正確等等。校驗通過后,如果這個服務是第一次注冊,Nacos 會在服務端生成一個 Service 對象,然后把這次注冊的實例信息存入這個 Service 對象中;如果 Nacos 服務端已經有了這個 Service 對象,那么就會直接把新注冊的實例信息存入對象。這個 Service 對象通過 命名空間+Group+Service 的組合來保證唯一性。
完成實例存入 Service 的同時,會觸發兩個事件,其中一個事件是用於數據同步的,Nacos 服務端會根據這個服務是否是臨時對象的信息,使用 Distro 或者 Raft 協議進行同步,通知其他的 Nacos 節點該服務發生了變更;另一個事件則通知在該 Nacos 服務節點上訂閱了該服務的訂閱者,並根據訂閱者信息,通過 UDP 的方式,把最新的服務列表推送到訂閱者客戶端上。這就完成了一次服務注冊流程。
另外,對於那些被定義為持久化的服務的所有信息,都會通過 raft 協議,保證能夠寫入到文件系統中被持久化。
最后,其他的 Nacos 節點,在通過同步而進行 Service 變更的時候也會觸發通知訂閱者的事件,從而使在其他 Nacos 服務節點上訂閱該服務的訂閱者也能收到推送。
1.X 架構存在的問題
粗略介紹了下 Nacos1.X 的架構和服務發現模型,接下來分析一下 Nacos1.X 架構所面臨的幾個比較重要的問題。
一句話總結,心跳多,無效查詢多,心跳續約感知變化慢,連接消耗大,資源空耗嚴重。
- 心跳數量多,導致 TPS 居高不下
通過心跳續約,當服務規模上升時,特別是類似 Dubbo 的接口級服務較多時,心跳及配置元數據的輪詢數量眾多,導致集群 TPS 很高,系統資源高度空耗。
- 通過心跳續約感知服務變化,時延長
心跳續約需要達到超時時間才會移除並通知訂閱者,默認為 15s,時延較長,時效性差。若改短超時時間,當網絡抖動時,會頻繁觸發變更推送,對客戶端服務端都有更大損耗。
- UDP 推送不可靠,導致 QPS 居高不下
由於 UDP 不可靠,因此客戶端測需要每隔一段時間進行對賬查詢,保證客戶端緩存的服務列表的狀態正確,當訂閱客戶端規模上升時,集群 QPS 很高,但大多數服務列表其實不會頻繁改變,造成無效查詢,從而存在資源空耗。
- 基於 HTTP 短連接模型,TIME_WAIT 狀態連接過多
HTTP 短連接模型,每次客戶端請求都會創建和銷毀 TCP 鏈接,TCP 協議銷毀的鏈接狀態是 WAIT_TIME,完全釋放還需要一定時間,當 TPS 和 QPS 較高時,服務端和客戶端可能有大量的 WAIT_TIME 狀態鏈接,從而會導致 connect time out 錯誤或者 Cannot assign requested address 的問題。
- 配置模塊的 30 秒長輪詢引起的頻繁 GC
配置模塊使用 HTTP 短連接阻塞模型來模擬長連接通信,但是由於並非真實的長連接模型,因此每 30 秒需要進行一次請求和數據的上下文切換,每一次切換都有引起造成一次內存浪費,從而導致服務端頻繁 GC。
Nacos 2.0 架構及新模型
Nacos 2.0 架構層次
Nacos 2.X 在 1.X 的架構基礎上 新增了對長連接模型的支持,同時保留對舊客戶端和 openAPI 的核心功能支持。
通信層目前通過 gRPC 和 Rsocket 實現了長連接 RPC 調用和推送能力。
在服務端測,新增一個鏈接層,用來將不同類型的 Request 請求,將來自不同客戶端的不同類型請求,轉化為相同語意的功能數據結構,復用業務處理邏輯。同時,將來的流量控制和負載均衡等功能也會在鏈接層處理。
其他架構分層在大體上保持不變。
Nacos 2.0 新服務模型
雖然 Nacos2.0 的在架構層次上並未做太大的變化,但是具體的模型細節卻有不小的改動,依舊使用注冊服務的流程,再深入了解一下 Nacos2.0 服務模型的變化。
由於通信使用了 RPC 方式,因此某一客戶端的所有請求(無論是注冊還是訂閱)都通過同一個鏈接和同一個服務節點進行,不像之前通過 HTTP 連接可能每次請求都請求在不同的 Nacos 節點上,這就導致了服務發現的數據內容由原來的無狀態化變為了與連接狀態綁定的一種有狀態數據。為了適應這種變化,需要改變一下數據模型,因此抽象了一個新數據結構,將同一個客戶端通過該鏈接發布和訂閱的內容關聯起來,暫命名為 Client。這個 Client 不是客戶端的意思,而是這個客戶端所相關的數據內容,一個鏈接與一個 Client 對應。
當客戶端發布了服務時,該客戶端所發布的所有服務與訂閱者信息會被更新到與該客戶端鏈接相對應的 Client 對象中,然后通過事件機制觸發對索引信息的更新。這個索引信息是客戶端鏈接和服務的索引,方便快速聚合生成需要推送的服務緯度的數據。
索引信息更新完成后,會觸發推送事件,此時會將所有和該服務有關的 Client 對象,通過剛產生的索引信息聚合起來,當數據聚合完成后,再從客戶端鏈接中篩選出訂閱該服務的訂閱者的客戶端鏈接,將推送數據通過該鏈接,推送回去。這樣一次發布變更的主鏈路就完成了。
回過頭看數據同步,客戶端發布了服務時實際更新的對象從原來的 Service 變成 Client 對象,所以需要同步的內容也變成了 Client 對象;同時服務端間的通信方式也會換成 RPC。這里只有真正被客戶端更新的 Client 對象會觸發同步,如果是通過同步而更新的 Client 對象不會再次觸發同步。
最后看 Metadata,Metadata 是從 1.X 版本中的 Service 對象和 Instance 對象中分離出來的一些屬性:比如服務的元數據 label 標簽,實例的上下線狀態、權重和元數據 label 標簽等。這些元數據可以被 openAPI 單獨修改,在聚合數據時生效。之所以將元數據拆分出來,區別於基礎數據,原因是基礎數據比如:ip 端口,服務名等一經發布不應該被修改,而且應當以發布時的信息為准;但其他的原數據,比如上下線狀態和權重,通常是在運行過程中動態調節的,因此拆分開之后,分為兩條不同的處理工作流應該更加合理。
Nacos 2.0 架構的優缺點
前面簡要介紹了 Nacos 2.0 的架構和新模型的工作方式,接下來我們分析一下這樣的改動有哪些優缺點。
優點
-
客戶端不再需要定時發送實例心跳,只需要有一個維持連接可用 keepalive 消息即可。重復 TPS 可以大幅降低。
-
TCP 連接斷開可以被快速感知到,提升反應速度。
-
長連接的流式推送,比 UDP 更加可靠;nio 的機制具有更高的吞吐量,而且由於可靠推送,可以加長客戶端用於對賬服務列表的時間,甚至刪除相關的請求。重復的無效 QPS 可以大幅降低。
-
長連接避免頻繁連接開銷,可以大幅緩解 TIME_ WAIT 問題。
-
真實的長連接,解決配置模塊 GC 問題。
-
更細粒度的同步內容,減少服務節點間的通信壓力。
缺點
沒有銀彈的方案,新架構也會引入一些新問題:
-
內部結構復雜度上升,管理連接狀態,連接的負載均衡需要管理。
-
數據又原來的無狀態,變為與連接綁定的有狀態數據,流程鏈路更長。
-
RPC 協議的觀測性不如 HTTP。即使 gRPC 基於 HTTP2.0Stream 實現,仍然不如直接使用 HTTP 協議來的直觀。
Nacos 2.X 規划
接下來簡單分享下 Nacos 2.X 的后期規划,主要分為文檔、質量和 Roadmap。
在文檔和質量方面,Nacos 1.X 都做的不是很好。文檔內容較少,僅有簡單使用文檔;和版本有一定脫節,更新不及時;沒有對技術內容的說明,參與貢獻難度高。代碼質量及測試質量也不是很高,雖然已經使用 checkstyle 進行了 codeStyle 的校驗以及開啟了社區協作 review。但是這還遠遠不夠。Nacos 2.X 將會逐步更新、細化官網使用文檔;通過電子書對技術細節進行解析;通過 Github 展示技術方案,促進討論及貢獻;並且對代碼進行大量重構及 UT 和 IT 的治理工作,在未來將 Benchmark 也會開源出來,方便給開源用戶進行壓測。
而 RoadMap 方面,Nacos 2.X 會對項目做大幅度的重構,完成初步插件化,並對剛才 2.0 架構的一些缺點,如負載均衡,可觀測性進行提升。
加入我們
歡迎在 Nacos github 上提交 issue 與 PR 進行討論和貢獻,或加入 Nacos 社區群參與社區討論。
除了參與開源,我們也歡迎更多有能力及有意願的同學加入阿里雲共建雲原生,詳情請看雲原生應用平台。
本文整理自 Spring Cloud Alibaba Meetup 杭州站演講,點擊此處立即參與 1 月 9 日下周六的上海站 Meetup,聽 Nacos 用戶分享 Nacos 在知名互聯網教育公司的落地實踐。
作者簡介
楊翊,花名席翁。Nacos PMC,主要參與的是服務發現模塊,和做一些內核重構和提升的工作。Apache SharadingSphere PMC,主要負責和參與過的模塊有 路由模塊、分布式事務、 數據同步、以及彈性擴容。