華為雲釋出冷啟動加速解決方案:助力Serverless計算速度提升90%+

2023-01-29 18:02:06
摘要:本文介紹了華為雲對冷啟動優化這一業界難題的探索之路,創新提出了基於程序級快照的優化方案。

作者資訊——

子游:華為元戎高階工程師

平山:華為雲中介軟體 Serverless 負責人

琪君:華為元戎負責人

Key Takeaways

  1. 冷啟動 (Cold Start)一直是Serverless領域面臨的優化難題之一,華為雲創新提出了基於程序級快照的冷啟動加速解決方案,致力於在使用者幾乎無感知的前提下,有效提升應用的冷啟動效能;
  2. 特別的,Java應用冷啟動速度慢的問題尤為突出。本文以Java場景為例,介紹華為雲在冷啟動效能優化方面的探索歷程,並揭祕90%+效能提升背後的技術實現原理。文末我們也提供了Quick Start,幫助使用者更快地上手該新特性。

一、問題引言:Java應用冷啟動速度面臨巨大挑戰

Serverless應用啟動時,都需要先進行初始化。其初始化時長一般取決於應用本身的屬性,如業務邏輯、程式語言等,其中Java應用的初始化過程通常是最慢的。以下基於一個典型的Java應用,對其啟動時延進行拆解,各階段耗時分佈如圖1所示:

圖1:Java應用啟動耗時分解

其中,端到端冷啟動耗時可分為2大部分:

  • 平臺側時間:

主要包含執行環境建立(如容器啟動)、執行環境初始化(如程式碼包下載、部署)等準備工作,此階段最多是秒級響應,在冷啟動整體耗時中佔比很低,通常不到5%,平臺側也支援一些優化方式,將耗時進一步壓縮至毫秒級;

  • 服務側時間:

主要包含應用框架啟動(如構建Spring ApplicationContext)、業務初始化(如業務資料初始化)等動作,此階段耗時一般較長。在本例中,應用框架啟動耗時佔比約30%,業務初始化佔比約65%。由此推斷,該階段執行的動作是Java應用啟動慢的核心所在

Java應用啟動慢的根因其實也不難理解,主要有:

  • 框架複雜:Spring作為一個企業級的框架,為了支援廣泛的應用需求,存在大量的可設定和初始化邏輯,並通過複雜的設計模式來支撐這種靈活性。例如,一個spring-boot-web的hello world,依賴的class檔案就多達7404個,見圖2;
  • JVM的一次編譯,到處執行:類載入時,查詢類、校驗類的開銷會隨著應用複雜度而增長;同時,在應用剛啟動時,方法還沒有完全被JIT編譯完成,因此大部分情況停留在解釋執行,影響了應用啟動的速度。

圖2: hello world依賴的class個數

因此,對於時延敏感型的Java應用程式,在突發流量下發生冷啟動時,可能會導致使用者體驗下降。為了應對這一挑戰,使用者可以提前預留資源來減少冷啟動發生的頻率,或者對自己的應用進行效能調優,但是第一類方案無形中增加了使用者的keep-alive成本,第二類方案也有著較高的技術門檻且往往效果比較有限。

二、基於快照技術的冷啟動加速:華為雲的優化探索之路

Part I:站在巨人的肩膀上

業界針對Java應用的啟動速度優化已有一些優秀的實踐,可分為以下幾類:

  • AOT:
    主要有GraalVM[1]、EJET等,AOT方案是通過在程式執行前,直接將Java原始碼編譯成本地機器碼,因為提前編譯並不佔用執行時間,以此來顯著提升應用的啟動速度,同時本地機器碼可以持久化於磁碟中,不佔用記憶體且可重複使用。但是該類方案在特定場景也存在一定的侷限性,如GraalVM對反射的支援並不友好,在涉及反射的地方都需要新增設定;EJET雖然解決了反射的問題,但是其編譯時間較長且不穩定,在複雜應用場景下也存在效能劣化問題。
  • AppCDS[2]:
    AppCDS方案是通過在JVM啟動時從JSA檔案讀取共用資料,省略了共用類的載入過程,提升JVM啟動速度;同時,多個JVM共用同一個歸檔檔案,減少動態記憶體佔用,可以提升記憶體使用率。該類方案主要適用於類載入比較多的場景,在一般場景下提升有限,且其對共用類的支援有一定限制,如執行時動態生成類不支援共用等。
  • 其他針對性(Spring框架)方案:

如Lazy Initialization[3]、Scanning-index[4]等,前者通過懶載入的方式來減少啟動時載入類的數量,一定程度上提升啟動速度;後者通過在編譯階段建立索引,避免啟動時掃描所有路徑來進行加速。但是該類方案在Serverless場景缺乏一定的普適性。

華為雲FunctionGraph創新提出的基於程序級快照的冷啟動加速解決方案,致力於在使用者無感知(無需/少量進行程式碼適配)的前提下,幫助使用者突破冷啟動的效能瓶頸。本優化方案直接從應用初始化後的快照進行執行環境恢復,跳過複雜的框架、業務初始化階段,從而顯著降低Java應用的啟動時延,實測效能提升達90%+。

Part II:快照方案如何優化Java應用啟動速度

當用戶Java函數開啟冷啟動加速的設定開關後,華為雲FunctionGraph會預先執行函數對應的初始化程式碼,獲取其初始化執行上下文環境的快照,並進行加密快取。後續呼叫該函數並觸發冷啟動擴容時,會直接從提前初始化後的應用快照來恢復執行環境,而非重新走一遍初始化流程,以此達到極大提升啟動效能的效果。

先結合圖3直觀對比一下優化前、後的冷啟動流程差異:

圖3:基於快照加速的冷啟動流程

基於快照的冷啟動流程,主要包含以下幾個關鍵步驟:

Step 1:平臺側提前準備執行環境,並預執行初始化程式碼、儲存應用快照,此動作後續統稱為Checkpoint

  • 與圖1對應,此階段一般佔總耗時的90%左右。

Step 2:在請求到達,觸發函數新範例擴容時,直接從應用快照來恢復新的執行環境,此動作後續統稱為Restore

  • Restore 耗時是秒級,相當於將數十秒完整的初始化時間(在圖 1 的範例中)縮短至秒級 Restore 耗時,啟動效能提升了一個數量級。

Step 3:(可選)應用程序從快照恢復後,執行Restore Hook完成業務狀態的重新整理

  • 由於Image File是程序執行時的快照,在重建程序之後,會涉及到程序持有狀態的有效性更新。例如已建立的外部連結、載入到程序裡的快取資訊等。故我們引入了Restore Hook的概念,提供手段讓業務對這些狀態進行重新整理,詳見Part IV。

Step 4:應用Ready,具備接著往下執行業務邏輯的能力

特別的,容器本身也是主機上的程序,故本優化方案也支援容器粒度的Checkpoint,即對容器內指定程序進行CR,與傳統的輕量化虛機快照相比,其精細化程度更高、也更靈活。其原理詳見圖4:

圖4:基於容器的CR流程

  1. 在Source機器上啟動微服務,通過健康檢查和初始化呼叫後,進行Checkpoint,停止服務,生成程序快照資訊;
  2. 在Source機器上將程序快照資訊和微服務所有相關依賴,進行壓縮,加密生成記憶體快照包,並上傳至雲端儲存。
  3. 在Target機器上從持久化儲存中下載對應微服務的記憶體快照包,進行解壓恢復。
  4. 在Target機器上Restore微服務程序;

Part III:快照技術揭祕

華為雲提出的基於程序級快照的冷啟動加速方案,其核心技術依託於CRIU[5],它支援對使用者空間指定的程序進行「凍結」(即停止程序,並將該程序執行的所有上下文持久化為映象檔案),並在必要時對其進行「解凍」(即通過儲存的映象檔案來正確恢復程序執行的上下文),其核心工作流程如圖5-6所示[6]:

圖5:CRIU如何工作——Checkpoint

圖6:CRIU如何工作——Restore

Checkpoint

    1. CRIU首先通過作業系統的 /proc 目錄獲取指定程序和該程序下所有子程序的資訊,包含檔案描述符(/proc/$pid/fd)、管道引數、網路設定和記憶體對映檔案(/proc/$pid/maps)等;
    2. CRIU接著通過Linux 的ptrace syscall介面把一段特殊程式碼動態注入到該程序的地址空間,通過執行該動態程式碼,CRIU以UNIX守護行程的方式收集dumpee程序存放在暫存器裡的記憶體資料;
    3. CRIU將所有程序資訊都收集完畢後,再次呼叫ptrace介面,去掉動態注入的程式碼,恢復該程序的原有程式碼;
    4. CRIU根據收集的程序記憶體資訊,生成多個以功能分類的映象檔案,並預設殺死程序,完成Checkpoint;

Restore

    1. CRIU解析Checkpoint階段生成的映象檔案,並分析多程序的共用資源;
    2. CRIU通過Linux 的fork 介面重新構建、恢復程序和其共用資源;
    3. CRIU恢復所有任務的資源,但不包含記憶體對映地址,定時器,執行緒等;
    4. CRIU根據映象檔案重新對映記憶體空間,切換程序上下文,恢復程序的繼續執行,完成Restore;

Part IV:Restore Hook

如Part II所述,雖然本優化方案能極大提升Java應用的冷啟動速度,但是快照技術在某些場景也存在一定的侷限性,較難做到對現有應用的全透明化。通過快照恢復後,應用的網路連線狀態會受到影響,涉及到TCP Socket重連等場景,如服務註冊、DB連線,分散式通訊,訊息佇列等。

這部分場景依賴應用本身的網路重連機制來更新正確,因此,本優化方案中也引入了Restore Hook的概念,提供手段讓業務對這些狀態進行重新整理。

Restore Hook當前已支援大部分主流第三方元件的重連,詳見圖7:

圖7:Restore Hook支援的第三方元件

不難發現,Restore Hook需要應用本身進行少量的程式碼適配。為了進一步簡化應用的改造負擔,我們也進行了一種新的技術嘗試,可以理解其充當了使用者應用與BaaS之間的紐帶,通過狀態解除安裝等手段,對開發者透明,幫助應用完成狀態的自動化重新整理。這部分探索會在後續的技術博文中跟大家分享,敬請期待。

三、效果實測:Java冷啟動時延降低90%+

我們選取了公司內部典型的Java應用,對其原始初始化流程、Restore流程進行了對比測試,如圖8所示。測試結果表明,本優化方案將應用的啟動速度平均提升了95%+,即使快照包的增大一定程度上增加了包下載、解壓的耗時,但最終端到端的冷啟動時延也降低了90%+。

圖8:冷啟加速前後的資料對比

四、快速上手:基於華為雲FunctionGraph的簡單實戰

華為雲釋出的基於程序級快照的冷啟動加速方案,是一種效能優化服務,使用者無需額外付費,只需進行簡單的設定、少量的程式碼修改,即可享受到該創新方案帶來的冷啟動效能提升。

下文基於華為雲FunctionGraph,為大家帶來特性Quick Start

1、登入FunctionGraph控制檯,建立Java函數,並開啟「快照式冷啟動」開關

2、(可選)設定Restore Hook,並在函數程式碼中實現對應的Hook邏輯

3、函數釋出新版本後,觸發快照的自動化製作

4、請耐心等待快照製作完成(5min超時時間)

5、呼叫Java函數,體驗快照優化後的效能提升

五、總結與展望

本文介紹了華為雲對冷啟動優化這一業界難題的探索之路,創新提出了基於程序級快照的優化方案。當然,本方案也並非十全十美,它依然面臨著一系列挑戰,如文中提到的應用狀態重新整理、程序級CR的精細化控制、多平臺的相容性等,我們也在持續探索、優化中。

同時,FunctionGraph 作為華為元戎核心加持的下一代 Serverless 函數計算與編排服務,致力於持續為使用者提供方便、迅捷的Serverless 服務體驗。您可以登入華為雲FunctionGraph控制檯來深入體驗,更多資訊請參閱FunctionGraph官方檔案[7]。後續我們將分享更多圍繞通用全場景 Serverless的前沿理論及其案例實踐,回饋社群。

參考資料

[1]https://www.graalvm.org/22.3/reference-manual/java/compiler/

[2]https://wiki.openjdk.org/display/HotSpot/Application+Class+Data+Sharing+-+AppCDS

[3]https://spring.io/blog/2019/03/14/lazy-initialization-in-spring-boot-2-2

[4]https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-scanning-index

[5]https://github.com/checkpoint-restore/criu

[6]https://speakerdeck.com/udzura/introduction-to-criu?slide=32

[7]https://support.huaweicloud.com/functiongraph/index.html

 

點選關注,第一時間瞭解華為雲新鮮技術~