数か月前、私たちは Encore.ts (TypeScript 用のオープンソース バックエンド フレームワーク) をリリースしました。
世の中にはすでに多くのフレームワークがあるため、私たちが行った異常な設計上の決定のいくつかと、それがどのようにして顕著なパフォーマンス数値につながるのかを共有したいと思います。
私たちは最近、Encore.ts が Express.js と比較して 9 倍、Fastify と比較して 2 倍のリクエスト スループットを達成することを示すパフォーマンス ベンチマークを公開しました。
今日は、Encore.ts がどのようにして信じられないほど高速な コールド スタート起動時間を達成するのかを詳しく見て、パフォーマンスの旅を続けます。
今回は、Encore.ts、Fastify、NestJS、Express のベンチマークを実施し、コールド スタートアップ時の各フレームワークのパフォーマンスを確認しました。
ベンチマーク プログラムは、それぞれ単純なスキーマを持つ 10 個の API エンドポイントを登録し、スキーマ検証をセットアップします。
スキーマ検証には、可能な限り Zod を使用しました。
Fastify の場合、公式にサポートされているスキーマ検証ライブラリとして Ajv を使用しました。
JavaScript コードの実行が開始されてから、サーバーが受信リクエストを受け入れる準備ができるまでの時間を測定しました。
各ベンチマークについて、5 回の実行のうち最良の結果を採用しました。
話はこれくらいにして、数字について詳しく見ていきましょう!
(GitHub でベンチマーク コードを確認してください。)
ご覧のとおり、Encore.ts は、Express の 5 倍以上、NestJS の 17 倍以上という驚くべき高速コールド スタートアップ時間を実現しています。
これはどのようにして可能ですか?テストの結果、パフォーマンスの 2 つの主要な原因が特定されました。どちらも Encore.ts が内部でどのように動作するかに関連しています。
しかし、そこに着く前に、コールドスタートとは実際何なのか、そしてなぜそれが重要なのかについて話しましょう。
サーバーレスのコンテキストでは、コールド スタートとは、受信リクエストに対応するために基盤となるプラットフォームが最初にサーバーの新しいインスタンスを起動する必要があるときのことです。 (デプロイ後など、リクエストを処理するためにサーバーの新しいインスタンスが初めて起動されるときを指すこともあります。)
プロセスが起動してリクエストを処理する準備ができるまで、リクエストは事実上保留されるため、コールド スタートアップ時間を短縮すると、アプリケーションのロングテール レイテンシに大きな影響を与える可能性があります。
これは、リクエストを処理するときにシステムの一部でコールド スタートが発生する可能性が非常に高いため、複数のサーバーレス機能がある分散システムでは特に重要です。
コールド スタート中に何が起こるかは、デプロイ先のプラットフォーム (Kubernetes、Lambda、Cloud Run など) によって多少異なります。
ただし、一般的に、プロセスは次のようになります:
これらの初期化手順の後、コールド スタートが完了し、サーバーレス関数が受信リクエストの処理を開始します。
最初の 2 つのステップは、コード/コンテナのサイズが最適化されていることを除いて、私たちの制御の範囲外であるため、3 番目のステップに注目してみましょう。
実際、Node.js を実行していると仮定して、3 番目のステップをさらに詳しく見てみましょう。
最後に、すべての依存関係がロードされ、すべての初期化コードが実行されると、コンテナ/サーバーレス関数は受信リクエストを処理する準備が整います。
上記の内訳により、最適化の明確な目標が得られ、Encore.ts は制御可能なすべてのステップを大幅に最適化します。
Encore.ts は Rust で実装され、ネイティブ モジュールとして Node.JS にロードされます。これには、コールド スタートにいくつかの利点があります。
解析および実行する JavaScript が少なくなります。 JavaScript はインタープリタ型言語であるため、すべての JavaScript コードをディスクから読み取り、解析し、実行する必要があります。 Encore.ts は、コンパイル済みのネイティブ モジュールとして非常に高速に読み込まれるため、JavaScript エンジン (V8) で解析したり実行したりする必要はありません。
NPM 依存関係はゼロです。 Encore.ts は Rust を使用してすべての機能を実装しているため、NPM への依存関係がまったくなく、コールド スタート中に実行する必要がある JavaScript の量がさらに削減されます。
コンパイル済みおよび最適化済み。 JavaScript は、繰り返し実行されるコードが JavaScript エンジンによって最適化される、ジャストインタイム コンパイル (JIT) に大きく依存しています。これはインタープリター型言語にとっては非常に理にかなっていますが、コードの一部を初めて実行するときの実行がかなり遅くなり、コールド スタートに大きな影響を与えることも意味します。 Encore.ts は Rust で実装されているため、事前にコンパイルされ、実行されているプラットフォームに合わせて大幅に最適化されています。つまり、初回実行時から高速です。
Encore.ts はデフォルトで、トランスパイルされた JavaScript とアプリケーションの実行に必要な依存関係のみを含めて、縮小された Docker イメージをビルドします。これによりバンドル サイズが小さくなり、コンテナのダウンロードと起動にかかる時間が短縮されます。
さらに、いくつかのコンピューティング プラットフォームでは ストリーミング Docker イメージ のサポートが追加されました。これは、イメージ全体がダウンロードされる前にプラットフォームがコンテナを開始できることを意味します。 Encore.ts にはこれに対するサポートが組み込まれており、コールド スタートを減らすために必要なイメージの部分に自動的に優先順位を付けます。
Rust ランタイムと最適化された Docker イメージを組み合わせることで、Encore.ts は驚くべきコールド スタート時間を実現でき、これはアプリケーションのロングテール レイテンシに大きな影響を与える可能性があります。
プロジェクトにとってパフォーマンスが重要な場合は、Encore.ts を試してみることをお勧めします。
すべてオープンソースなので、コードをチェックアウトして GitHub に投稿できます。
または、ぜひ試してみて、ご意見をお聞かせください!
以上がEncore.ts — NestJS や Fastify よりも高速なコールド スタートの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。