Man page of CHIKU_WAIT(2)

システムソフトウェアとポエムの差が激しいので,高山病に注意

論文紹介:Catalyzer: Sub-millisecond Startup for Serverless Computing with Initialization-less Booting

概要

  • タイトル:Catalyzer: Sub-millisecond Startup for Serverless Computing with Initialization-less Booting
  • 著者:Dong Du,Tianyi Yu,Yubin Xia,Binyu Zang,Guanglu Yan, Chenggang Qin,Qixuan Wu,Haibo Chen
  • 会議:ASPLOS '20: Proceedings of the Twenty-Fifth International Conference on Architectural Support for Programming Languages and Operating Systems

https://dl.acm.org/doi/abs/10.1145/3373376.3378512

3月のASPLOSで出た論文です. サーバレス環境では,低レイテンシでの関数の実行が非常に重要です. しかし,仮想化ベースのサンドボックス設計は起動にかかる時間が課題です. この論文では,強力な分離と非常に高速な起動の両方を提供するgVisorベースのサーバーレス向けサンドボックスのCatalyzerを提案しています. Catalyzerは,チェックポイントイメージから仮想化ベースの機能インスタンスを復元することで,初期化をスキップしています. また,実行中のサンドボックスインスタンスの状態を直接再利用して起動のかかるレイテンシを減少させるために,新しいOSプリミティブsforkを提案しています.

Catalyzerは,状態を再利用することで初期化コストを取り除くことで,サーバーレスの一般的な最適化を可能にしています. このブログでは,論文の全般的な内容を紹介していこうと思います.

起動にかかる時間に関する最適化の分析

キャッシュによる最適化

SOCK*1では,AndroidのZygoteのアイデアをサーバレスに活用し,事前にウォームアップされたPythonインタプリタのキャッシュを作成しています. 必要なライブラリをすでにロードしているインタープリタを使用することで,高い起動パフォーマンスを実現しています.

SAND*2では,同一のアプリケーション関数のインスタンスが,サンドボックスを共有しています.

しかしこの論文では,1台のマシンですべての関数をキャッシュするとオーバヘッドが大きくキャッシュポリシも決定が難しいこと,テールレイテンシの削減はできないことからキャッシュが最適ではないとしています.

サンドボックスの最適化

ゲストカーネルのカスタマイズ,ハイパーバイザのカスタマイズといった起動遅延を最適化するための方法があります. 例えば,FireCrackerは仮想マシン(マイクロVM)と最小化したLinuxカーネルを100ms程度でブートすることを実現しています. しかし,この手法はJVMPythonインタプリタのようなアプリケーション初期化の遅延を緩和できないという課題が述べられています.

この論文の著者らは起動レイテンシを評価した結果,オーバヘッドの多くは遅延オーバーヘッドの多くはアプリケーションの初期化に起因していると述べています. JavaPythonのような高レベル言語では,アプリケーションをロードする前に言語ランタイム(例:JVM)を初期化する必要があるため,起動時の待ち時間が非常に長くなっています. また,サンドボックスの初期化は様々なワークロードに対して安定しており,Python Helloのような単純な関数になると初期化がオーバヘッドの多くを占めるようになります. そして,既存の仮想化ベースのサンドボックスでは,JVMまたはPythonインタプリタが原因で発生するアプリケーション初期化の待ち時間を短縮できません.

Checkpoint/Restoreによる最適化

Checkpoint/Restore(C/R)は,実行中のサンドボックスの状態を保存する手法です. アプリケーションの状態とサンドボックスの状態の両方が含まれているイメージからサンドボックスを復元し,シームレスに実行できます.

C/Rは,アプリケーションの初期化コストをサンドボックスの復元コストに変換できるという利点があります. しかし,システム状態(オープンされたファイルのようなカーネル内の状態)を回復するための再実行操作に依存します. やり直し操作はチェックポイントされたインスタンスの状態を回復し,正確さと互換性のために必要です. 例えば,開かれたファイルを再び開くためにopen()を再実行します. しかし,仮想化ベースのサンドボックスでは,パフォーマンスのオーバーヘッドが発生してしまいます.

提案

この論文では,仮想化ベースのサンドボックスにおけるC/Rの遅延を防ぐために,init-lessなブートの設計であるCatalyzerを提案しています.

Catalyzerでは,コールドブート,ウォームブート,フォークブートの3種類のブートが定義されています. コールドブートは,プラットフォームが関数のイメージからリストアによってサンドボックスインスタンスを作成します. ウォームブートは,要求された関数の実行中のインスタンスがあり,実行中のインスタンスのインメモリ状態を共有します. フォークブートは,ホットブートであり,初期化をスキップするために,専用のサンドボックステンプレートが必要です. フォークブートは単一のテンプレートから任意の数のインスタンスをブートするようにスケーラブルになっています. Catalyzerは,C/Rベースのinit-lessブートと新しいOSプリミティブを組み合わせたハイブリッドアプローチを採用することでこの3種類のブートを実現しています.

実行段階のサーバレス関数は,初期化段階で使用されるメモリとファイルの両方のごく一部にしかアクセスしません. そこで,この提案手法では,アプリケーションとシステム状態の両方のリカバリを最適化するために,コールドブートとウォームブートのオンデマンドリストアが導入されています. そして,テンプレートサンドボックスの状態を直接再利用することで,フォークブートの起動遅延を短縮する新しいOSプリミティブであるsforkを提案しています.

オンデマンドリストア

この論文では,リストアのパフォーマンス・オーバーヘッドは,アプリケーションとシステム状態のメタデータの圧縮解除・デシリアライズとメモリへのロード,サンドボックスやI/O接続などのシステム状態を回復のためのやり直し操作の2つが原因であると述べられています. Catalyzerは処理をオフライン準備とクリティカルパスリストア,オンデマンドリカバリの3つの部分に分割しています. 圧縮解除やデシリアライズのような準備作業は,ほとんどがチェックポイント段階でオフラインで行われます.

また,オンデマンドページングとI/O再接続によって,アプリケーション状態のロードとI/O関連システム状態の回復が遅れると述べられています. Catalyzerは,クリティカルパス上で最小限の作業,つまり非I/Oシステム状態の回復のみを行うことで,この遅延の解決を目指しています. 遅延を解決するために,Catalyzerはオーバレイメモリ,分離状態の回復,オンデマンドI/O接続,仮想化サンドボックスZygoteの4つの技術を提案しています.

オーバーレイメモリは,Catalyzerがファンクイメージをメモリに直接マップすることで,アプリケーション状態のロードをします. また,同じ関数を実行するサンドボックスは「ベースメモリマッピング」を共有することで,ファイルマッピングのコスト(ウォームブート用)を削減しています.

分離状態の回復では,クリティカルパス上のシステム状態回復からデシリアライズを分離します. オフライン準備中,Catalyzerは部分的にデシリアライズされたメタデータを関数のイメージに保存します. 次に,ポインタのオフセットからポインタ値のオフセットへのマップを格納するリレーションテーブルに,すべての参照関係を記録することで,メタデータオブジェクトとリレーションテーブルは,共に部分的にデシリアライズされたオブジェクトを構成します.

オンデマンドI/O再接続はI/O状態の回復を遅らせます. 接続の再確立は遅延し,ネクションが使用されたときに実行します. これを達成するために,I/O再接続は復元クリティカルパス上で非同期的に実行され,サンドボックス内のゲストカーネルは,I/O接続ステータスを維持します. つまり,ファイルディスクリプタは関数に渡されるが,ゲスト・カーネル内ではまだ再オープンされていないとタグ付けされることになります.

Zygoteはストア中に機能固有のサンドボックスを生成するために使用される一般化された仮想化サンドボックスです. また,キャッシュを利用してサンドボックス構築のオーバーヘッドを軽減しています. サンドボックスは構成ファイルとrootfsで構成されており,構成ファイルを解析し,仮想化リソース(例:vCPU)を割り当て,基本rootfsをマウントします. そして,関数呼び出し時にCatalyzerは,関数固有のバイナリ/ライブラリをインポートし,関数固有の設定をZygoteに追加します.

sfork

sforkは,実行中のテンプレートサンドボックスの状態を直接再利用することにより,起動待ち時間のさらなる低減を実現しています. テンプレートサンドボックスは,ユーザー要求に関する情報を持たない特定の機能のための特別なサンドボックスであり,リクエストを処理するためにサンドボックスインスタンス化するために利用されています. 最初に,テンプレートの初期化によってテンプレートサンドボックスが生成されます. そして,関数の要求が到着すると,テンプレートサンドボックスは自身をforkし,初期化された状態を直接再利用します. ここでの状態には,ユーザ状態(アプリケーションとランタイム)とゲスト・カーネル状態の両方が含まれます.

評価

いくつか評価をしていますが,アプリケーションの起動にかかる時間の評価の部分について紹介します. この論文では,Docker,Hyper,gVisor,gVisor-restore,FireCrackerと,コールドブート(catalyzer-restore),ウォームブート(catalyzer-Zygote),フォークブート(catalyzer-sfork)を比較しています. 評価には,C(Hello-world・nginx),Java(Hello-world・SPEC-jbb),Python(Hello-world・Django),Ruby(Hello-world・Sinatra),Node.js(Hello-world・Web)を用いています.

結果,全てのアプリケーションで提案手法は一番良い性能を発揮しました. 特に,Catalyzer-sforkは,サーバーレス関数の起動待ち時間を1ms未満まで向上できています. Catalyzer-Zygoteは,Cで5ms,Javaで14ms,Pythonで9ms,Rubyで12ms,Node.jsで9msを達成しました. Catalyzer-restoreは,サンドボックスを初期化して関数イメージをメモリにマップするために,Catalyst-Zygoteよりも30ミリ秒多く必要でした.

まとめると,Cのhello-worldからJava-SPECjbbまでの多様なアプリケーションに対して,Catalyzerの改善が一般的に達成できることを示しています.

感想

CRIUを使ったCheckpoint/Restoreで高速化みたいのは読んだことありますが,この論文では更なる高速化のための提案や実装ですごいなあと思いました(KONAMI). 特にI/Oやメモリ周りはよく考えられているなあと思いました. 実環境を意識した話もちょくちょく触れられているので,こういう研究ができるようになりたい.

*1:Edward Oakes, Leon Yang, Dennis Zhou, Kevin Houck, Tyler Harter, Andrea C. Arpaci-Dusseau, and Remzi H. Arpaci-Dusseau. 2018. SOCK: rapid task provisioning with serverless-optimized containers. In Proceedings of the 2018 USENIX Conference on Usenix Annual Technical Conference (USENIX ATC ’18). USENIX Association, USA, 57–69.

*2:Istemi Ekin Akkus, Ruichuan Chen, Ivica Rimac, Manuel Stein, Klaus Satzke, Andre Beck, Paarijaat Aditya, and Volker Hilt. 2018. SAND: towards high-performance serverless computing. In Proceedings of the 2018 USENIX Conference on Usenix Annual Technical Conference (USENIX ATC ’18). USENIX Association, USA, 923–935.