天天看點

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

作者 | 楊翊(席翁)  Nacos PMC

來源|阿裡巴巴雲原生公衆号

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

Nacos 在阿裡巴巴起源于 2008 年五彩石項目,該項目完成了微服務拆分和業務中台建設,随着雲計算和開源環境的興起,2018 年我們深刻感受到開源軟體行業的影響,是以決定将 Nacos 開源,輸出阿裡十年關于服務發現和配管管理的沉澱,推動微服務行業發展,加速企業數字化轉型。

目前 Nacos 支援主流微服務開發語言 & 主流服務架構和配置管理架構,比如支援 Duboo 和 SCA, 還對接了一些雲原生的元件比如 coreDNS 和 sentinel 等。

用戶端語言方面支援諸如 Java、go python 等主流語言,還有近期剛釋出正式版本的 C# 和 C++,在此感謝所有社群貢獻者的支援。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

Nacos 開源 2 年多以來,共釋出了 34 個版本,其中有一些比較重要的裡程碑版本;Nacos 還非常年輕,有很大的進步空間,歡迎社群及各界大佬一起共同建設。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

接下來我們看一下 nacos1.x 架構及其分析一下存在的比較重要的問題。首先來看一下架構簡圖。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

Nacos 1.X 大緻分為 5 層, 分别是接入、通信、功能、同步和持久化。

接入層是使用者最直接互動的層面,主要有 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 服務發現模型。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

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 服務節點上訂閱該服務的訂閱者也能收到推送。

粗略介紹了下 Nacos1.X 的架構和服務發現模型,接下來分析一下 Nacos1.X 架構所面臨的幾個比較重要的問題。

一句話總結,心跳多,無效查詢多,心跳續約感覺變化慢,連接配接消耗大,資源空耗嚴重。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

心跳數量多,導緻 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.X 在 1.X 的架構基礎上 新增了對長連接配接模型的支援,同時保留對舊用戶端和 openAPI 的核心功能支援。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

通信層目前通過 gRPC 和 Rsocket 實作了長連接配接 RPC 調用和推送能力。

在服務端測,新增一個連結層,用來将不同類型的 Request 請求,将來自不同用戶端的不同類型請求,轉化為相同語意的功能資料結構,複用業務處理邏輯。同時,将來的流量控制和負載均衡等功能也會在連結層處理。

其他架構分層在大體上保持不變。

雖然 Nacos2.0 的在架構層次上并未做太大的變化,但是具體的模型細節卻有不小的改動,依舊使用注冊服務的流程,再深入了解一下 Nacos2.0 服務模型的變化。

支援 gRPC 長連結,深度解讀 Nacos 2.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 的架構和新模型的工作方式,接下來我們分析一下這樣的改動有哪些優缺點。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

用戶端不再需要定時發送執行個體心跳,隻需要有一個維持連接配接可用 keepalive 消息即可。重複 TPS 可以大幅降低。

TCP 連接配接斷開可以被快速感覺到,提升反應速度。

長連接配接的流式推送,比 UDP 更加可靠;nio 的機制具有更高的吞吐量,而且由于可靠推送,可以加長用戶端用于對賬服務清單的時間,甚至删除相關的請求。重複的無效 QPS 可以大幅降低。

長連接配接避免頻繁連接配接開銷,可以大幅緩解 TIME_ WAIT 問題。

真實的長連接配接,解決配置子產品 GC 問題。

更細粒度的同步内容,減少服務節點間的通信壓力。

沒有銀彈的方案,新架構也會引入一些新問題:

内部結構複雜度上升,管理連接配接狀态,連接配接的負載均衡需要管理。

資料又原來的無狀态,變為與連接配接綁定的有狀态資料,流程鍊路更長。

RPC 協定的觀測性不如 HTTP。即使 gRPC 基于 HTTP2.0Stream 實作,仍然不如直接使用 HTTP 協定來的直覺。

接下來簡單分享下 Nacos 2.X 的後期規劃,主要分為文檔、品質和 Roadmap。

在文檔和品質方面,Nacos 1.X 都做的不是很好。文檔内容較少,僅有簡單使用文檔;和版本有一定脫節,更新不及時;沒有對技術内容的說明,參與貢獻難度高。代碼品質及測試品質也不是很高,雖然已經使用 checkstyle 進行了 codeStyle 的校驗以及開啟了社群協作 review。但是這還遠遠不夠。Nacos 2.X 将會逐漸更新、細化官網使用文檔;通過電子書對技術細節進行解析;通過 Github 展示技術方案,促進讨論及貢獻;并且對代碼進行大量重構及 UT 和 IT 的治理工作,在未來将 Benchmark 也會開源出來,友善給開源使用者進行壓測。

支援 gRPC 長連結,深度解讀 Nacos 2.0 架構設計及新模型

而 RoadMap 方面,Nacos 2.X 會對項目做大幅度的重構,完成初步插件化,并對剛才 2.0 架構的一些缺點,如負載均衡,可觀測性進行提升。

楊翊,花名席翁。Nacos PMC,主要參與的是服務發現子產品,和做一些核心重構和提升的工作。Apache SharadingSphere PMC,主要負責和參與過的子產品有 路由子產品、分布式事務、 資料同步、以及彈性擴容。

繼續閱讀