天天看點

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

作者:阿裡終端技術
阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

繼 2019 年開源 Midway 架構之後,阿裡一直在 Node.js 的前沿進行深度研究,除了加入 TC39 參與标準化建設,向上遊 Node.js 項目持續貢獻,與龍蜥社群合作優化之外,也在 Serverless 領域有了不小的成果。

今天,向大家介紹我們最新的面向雲原生場景,面向 Serverless 架構下的新産品, 代号 Noslate。

Noslate 是什麼?

歡迎通路項目了解更多内容:https://github.com/noslate-project/noslate

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

JavaScript 是開發者數量最龐大的程式設計語言,早些年 Node.js 等技術的出現,讓 JavaScript 可以輕松地處理各類服務端任務。

但随着雲原生/Serverless 等新架構概念的引導,彈性效率成為了全新的架構設計目标。為了能夠讓 JavaScript 任務擁有更高的彈性效率,進而滿足在泛終端、全棧傳遞等領域的效率期待。我們逐漸深入探索的過程中逐漸形成了 Noslate Project,旨在提升雲原生場景下 JavaScript 的被排程性能,解決診斷性黑盒問題。

Noslate 它主要由三個子項目組成,分别展現了我們在提升 Javascript 任務彈性效率過程中碰到的問題以及解決方式:

  1. Node.js Distribution:初期針對函數計算冷啟動場景優化,降低 Node.js 使用者代碼加載耗時,形成了針對性的 Node.js 發行版本。
  2. Noslate Workers:随着探索的深入,我們設計了面向輕量端雲同構場景的 W3C Web-interoperable JavaScript 輕量化容器方案。在傳遞靈活度上和資源、執行效率上形成平衡,現在主要應用于中心化的 SSR 渲染等輕量任務場景,效果顯著。
  3. Noslate Debugger:在落地業務過程中,我們發現在彈性效率提升後,對于異常和崩潰變得難以定位,得益于 Linux 系統 Coredump 機制的啟發,我們設計了基于 Corefile 對問題進行離線診斷的 Noslate Debugger 産品,幫助使用者實作問題的回溯和實時定位。

簡而言之,Noslate 目标是通過提供完整的技術産品方案, 将 JavaScript 打造成雲原生時代最靈活的傳遞語言。

為什麼開源?

一方面我們希望通過開源加強項目産品化程度;另一方面希望在社群中吸收更多的實踐場景進而繼續完善産品設計,也歡迎大家參與到項目中來。

同時,依托阿裡雲龍蜥社群和 Anolis 作業系統的合作關系,我們得以在底層探索,實作技術的演進。

一、Noslate Workers

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

W3C Web-interoperable 運作時 Aworker,提供了一個輕量,近乎 0 冷啟動的 JavaScript Serverless 運作環境。通過它,可以輕松的在已有的架構中內建輕量化類 Serverless 的能力。

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

與傳統的 FaaS 架構不同是,這是一個在普通應用容器之上的輕量任務機關。得益于良好的動态任務高密度混部和隔離特性、以及基于任務狀态拷貝 API 帶來的近乎 0 冷啟動特性,可以實作任務的即用即啟與即停即抛,進而無需關心在整個大叢集中任務節點的編排問題。

與既有架構的關系:

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

Noslate Workers 由兩個主要元件組成:

  1. Aworker - 輕量、Web-interoperable JavaScript Runtime
  2. Noslated - Servlerss 化的 Aworker 排程管控實作

關于 Aworker

提供 Web API 标準的 Web-interoperable JavaScript 運作時,适合不直接依賴系統接口的業務邏輯部署。Aworker 實作了近似 Service Worker API 的規範,提供了基本的 Request-Response 服務 API。

因為提供了相比于 Node.js 的 API 更加高層次、抽象的定義,不會洩漏系統底層狀态,Aworker 通過 Startup Snapshot 和 Warmfork 能力, 實作了更快的水準及垂直擴容,能夠在毫秒級啟動并處理流量,具備更高的彈性效率。

亮點特性一:Warmfork

熟悉 Linux 系統程式設計的同學都知道 fork(2) 系統調用有幾個優勢:

  1. 新程序可以繼承母程序的目前狀态,而無需從 main() 開始初始化;
  2. pcb、棧、記憶體頁,頁表都是純記憶體複制,是以程序建立快 (<1ms);
  3. CopyOnWrite,新程序可以繼承母程序的靜态頁表,可節省系統記憶體;

對于 Node.js 來說,因為其無法在主線程持有所有多線程的狀态 (如鎖,信号量等),是以 Node.js 進行 fork 的修改難度很大。其多線程設計主要 來源于 libuv 庫和 V8 Platform Worker 線程:

  1. 因部分 IO 操作存在同步調用,如 dns,檔案讀寫等,是以 libuv 使用 IO 線程将同步操作轉換成異步操作;
  2. Node.js 的 V8 預設配置為多線程 GC、Background Compilation/Optimization 的方式;

Node.js 的單程序多線程模型可以由下圖表示:

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

Aworker 的設計是采用單程序單線程的模型,也就是将上述模型中的 worker thread 單獨抽出放到一獨立程序中。Worker 是以可支援 fork,進而避免從 main() 開始的啟動消耗,達到快速啟動的目的。

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

為了支援單線程,Aworker 還做了如下修改:

  1. 使用了 Linux AIO 特性替掉了 libuv 中同步的檔案系統操作(不是 POSIX AIO,兩者有差別。Posix AIO 類似于 libuv 現有的實作);
  2. 使用 V8 的 SingleThread 模式,這是一個給低端裝置(Low-end devices)實作的能力,不過非常符合 Serverless 資源模型;

而為了管理、隔離這些工作程序,我們需要一個輕量的業務程序容器管理元件 Turf ,該元件用于能通過 Warmfork 方式建立新的 Aworker 服務程序,并能提供一定的資源、環境的隔離能力,同時相容 OCI。差別于傳統 runc, rund 的容器,turf 旨在承載如 Aworker 這類輕 JS Runtime,它無需鏡像運作,開銷更低,可以支援更高的部署密度。

Alinode Warmfork 具體的對比:

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

提供 "被複制" 的程序,稱為 "種子程序",其他服務程序都是該程序的克隆。譬如 Aworker 作為種子程序,它需要确定自己一個 "可被克隆" 的時間點,将自己的所在狀态(記憶體)作為克隆程序的初始狀态。

Warmfork 的系統時序如下:

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

亮點特性二:Startup Snapshot

Warmfork 能解決了單機上服務程序的快速啟動,對于冷機啟動需要采用 Startup Snapshot 方案。Startup Snapshot 和 CodeCache 的差別在于 Startup Snapshot 能夠儲存使用者代碼邏輯執行狀态,而 CodeCache 隻儲存代碼解析結果、仍然需要重新執行 使用者代碼邏輯。

設計上,Startup Snapshot 可提供攜帶使用者代碼邏輯的快速恢複,但是也有局限性:

  1. Startup Snapshot 對記憶體開銷敏感,如果應用啟動階段用了大量記憶體,可能造成負優化;
  2. 使用者代碼啟動需要沒有歧義的狀态,比如 IP 位址、日期、連接配接狀态、服務發現結果等,針對這些歧義内容使用者代碼需要在程序恢複時有修正能力;

V8 的 Startup Snapshot Serializer 就是一個類似于 GC 的對象周遊器。這個周遊器通過周遊加入到 Snapshot 中的 Root 對象,周遊它所對應的對象圖并按照對象關系生成一系列的反序列化指令。

Startup Snapshot 相當于從 V8 Context 對象與它的 globalThis 開始,周遊堆中所有的對象并将對象關系與引用序列化成 特有的位元組碼,形成一個線性的可存儲狀态。并在恢複時,解釋執行這些位元組碼,恢複堆中的對象内容與他們之間的引用關系。

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

上述的兩類和被排程性能相關的特性被統一歸類為狀态拷貝 API,具體使用可以參考官網文檔中的《狀态拷貝 API》章節[1],詳細介紹了指令行參數和程式内的 Events。https://noslate.midwayjs.org/docs/noslate_workers/aworker/serialize-api/

Noslated

Noslate Container Deamon,作為 Noslate Workers 解決方案的核心管控程式,提供了執行個體排程、彈性擴縮容、配置管理、流量管理等能力。

基于健壯性考慮,它由兩個角色組成:控制面(Control Plane)、資料面(Data Plane)

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

Noslated 對于執行個體的管控主要有三個模式:

  1. 基礎模式 - 基于流量的擴縮容
  2. 即抛模式 - 運作完即銷毀
  3. 預留模式 - 面向曆史場景相容,在此不額外展開,詳情可以查閱官網【預留政策】。

1、基礎模式

當流量進入 Data Plane 後,如果沒有能夠處理請求的 Worker 執行個體,會通過 requestQueueing 事件通知 Control Plane,它會根據目前水位決定擴容數量,如果目前已無法建立 Worker 執行個體,會傳回資源上限報錯。新的 Worker 執行個體啟動後,會自動連接配接到 Data Plane,Data Plane 發現新的 Worker 執行個體連接配接後會主動觸發初始化請求,初始化成功後開始消費請求隊列裡堆積的請求。

當 Worker 執行個體閑置一段時間後,Control Plane 會主動發起 GC 操作,告知 Data Plane 關閉流量,流量關閉後,Control Plane 會通知 Turf 關閉 Worker 執行個體,清理資源殘留。

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

2、即抛模式

針對特定的靈活場景,一次性的輕量使用者腳本執行(比如特别高密度的混部執行二方任務如 SSR),為了隔離不同請求間的上下文,可以針對每個請求建立一個執行個體,并在執行後銷毀。

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

比如普通的 Node.js 執行個體帶上業務邏輯啟動一般都不會太快,如果直接用了響應使用者流量會難以接受。得益于 Aworker 運作時并配合 Warmfork [2]以及 Startup Snapshot [3]能力,更快完成 Worker 執行個體啟動。亦可把一部分業務自己的初始化邏輯放置到 Warmfrok 特性中,進而讓新執行個體都是最少的初始化時間,這才讓高密度混部二方任務成為可能。

3、預留模式

在此不額外展開,詳情可以查閱官網【預留政策】[4]。

二、Noslate Debugger

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

Noslate Debugger 是針對 V8 應用的離線分析工具,它可以分析 Node.js 等應用程式産生的 Corefile (Core 檔案):

  1. 檢查 Node.js/V8 應用程式的結構體、堆棧等内容
  2. 檢查 V8 堆内的各種對象資訊
  3. 從 Corefile 中導出 Heap Snapshot
  4. 業務無感擷取 Corefile (通過 Arthur 工具)
  5. 已支援 Node.js / AWorker LTS 官方發行版

為了更好的解決問題而不是造輪子,在未來的幾個月 Noslate Debugger 也會和國内社群 Node.js 穩定性領域優秀的開源軟體 Easy Monitor 共建整合,在 Node.js/V8 的問題診斷領域形成合力,也是值得期待的事情。

優點一:基于 Corefile 的 "快照" 更适應 Serverless

Serverless 應用通常會使用大量生命周期短、規格小的任務執行個體,但在此類任務執行個體上獲得調試診斷能力并不容易,這使得 Serverless 應用長期處于較為黑盒的窘境。比如,Inspector 需要穩定和長時的網絡連接配接、運作時 Heap Snapshot 需要較多的計算和記憶體資源,都是和 Serverless 架構背道而馳的。

不管是 V8 的對象還是堆快照,它都是 "資訊" 在記憶體中的存儲,而 Inspector 功能就是可以在 "運作時" 能提取這些資訊。Noslate Debugger 通過 Corefile 将這部分調試診斷能力轉移到了離線時進行,讓原有實時性要求高的線上診斷調試轉化為隻需簡單檔案上傳即可內建使用。

在使用者本地或雲端服務上提供接近使用者本地開發時的調試診斷體感:

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案
Corefile (特指 GNU Corefile 格式) 主要記錄的是 Node.js 程序的記憶體和寄存器轉儲(CoreDump: 記憶體到磁盤的過程)。是以它也是程序完整“資訊”,被用于 Linux 系統應用 Crash(有損) 的調試載體,也可用于 GCore(無損) 産生程序快照用于離線分析。

優點二:更小的業務影響

對比原有線上 "堆快照" 對業務的影響長達數分鐘,到隻影響業務 RT 秒級(通過 GCore),甚至隻有幾十毫秒 (通過 Arthur 工具)。Corefile 快照也不會有任何運作時的"添油加醋",是以它也适合那些還未被GC的對象定位,譬如診斷已經結束了的業務處理等。

Arthur 是 Noslate Debugger 中用于低影響擷取 core檔案的工具,利用 fork 減少程序暫停時間,LZ4 壓縮減少轉儲體積。帶業務流量的線上環境抓取,業務影響 31.106 毫秒,Corefile 大小為 338 MB (程序原使用 1.44GB 實體記憶體)。

三、Node.js 發行版

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

我們還對 Node.js 的執行個體進行了定向彈性場景的優化,提高了使用者代碼的加載速度,進而降低了冷啟動時間。主要包括 Require 關系加速、Bytecode Cache,優化效果提升可高達 100% ~ 200%。該發行版,同時包含來自阿裡雲基礎軟體團隊在 ARM 架構的性能優化特性。

冷啟動優化

PGO(Profile Guided Optimization),是一種根據運作時 Profiling Data 來進行編譯優化的技術,這裡我們借鑒了這一概念。主要是通過執行一遍之後收集啟動階段的熱點資料生成緩存檔案,後續通過記憶體映射直接加載高效的緩存檔案,即可獲得提升在 100% ~ 200% 的使用者代碼冷啟動優化效果。

阿裡巴巴 Noslate 正式開源 - 面向雲原生的 JavaScript 容器方案

面向特定平台架構優化

Node.js 支援包括 x64、arm64 等在内的多種架構。但針對 ARM 晶片的快速發展,上遊版本往往僅提供基礎适配,缺少針對新指令集的優化,導緻在 ARM 晶片上無法獲得潛在的性能提升。當下主流雲廠商大都提供了 ARM 架構、高成本效益的運作環境。Noslate Node.js 發行版針對 ARM 等平台的優化可以讓應用在這些架構上獲得更高的性能和效率。目前 Noslate Node.js 發行版已經在進行針對阿裡雲 Ampere、阿裡雲倚天的定制優化,未來計劃包括支援龍蜥社群中的其他架構。主要包括:zlib 特性優化、其他一些利用 SIMD 的性能提升都在 PR 合并和準别中。

詳細了解

上面是對 Noslate Project 的簡單介紹,如果想要詳細了解可通過下述方式:

  • GitHub: https://github.com/noslate-project/noslate
  • 網站:https://noslate.midwayjs.org/
  • 龍蜥社群 SIG(特殊興趣小組,有釘釘群):https://openanolis.cn/sig/web-platform
  • 郵件清單:[email protected]

緻謝

感謝阿裡巴巴集團内業務方的支援,同時還要特别感謝所有給本項目貢獻過代碼、一起探索過技術方向夥伴們(包括不限于 legendecas、mariodu、zhaolei0505、XadillaX、umuoy1、oraluben、hyj1991 等)。

參考資料

[1]官網文檔中《狀态拷貝 API》章節: https://noslate.midwayjs.org/docs/noslate_workers/aworker/serialize-api/

[2]Warmfork: https://noslate.midwayjs.org/docs/noslate_workers/aworker/intro/#warmfork

[3]Startup Snapshot: https://noslate.midwayjs.org/docs/noslate_workers/aworker/intro/#startup-snapshot

[4]預留政策: https://noslate.midwayjs.org/docs/noslate_workers/references/scale/#%E4%B8%89%E9%A2%84%E7%95%99%E7%AD%96%E7%95%A5

繼續閱讀