「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > Encore.ts — ElysiaJS や Hono よりも高速

Encore.ts — ElysiaJS や Hono よりも高速

2024 年 11 月 5 日に公開
ブラウズ:299

数か月前、私たちは TypeScript 用のオープンソース バックエンド フレームワークである Encore.ts をリリースしました。

すでに多くのフレームワークが存在するため、私たちが行った珍しい設計上の決定のいくつかと、それがどのようにして驚くべきパフォーマンス数値につながるのかを共有したいと思いました。

パフォーマンスのベンチマーク

以前、Encore.ts が Express の 9 倍、Fastify の 2 倍高速であることを示すベンチマークを公開しました。

今回は、2 つの最新の高性能 TypeScript フレームワークである ElysiaJS および Hono に対して Encore.ts をベンチマークしました。

スキーマ検証ありとなしの両方で各フレームワークのベンチマークを行い、ElsyiaJS と Hono での検証に TypeBox を使用しました。これは、これらのフレームワークでネイティブにサポートされている検証ライブラリであるためです。 (Encore.ts には、エンドツーエンドで機能する独自の型検証が組み込まれています。)

各ベンチマークについて、5 回の実行のうち最良の結果を取得しました。各実行は、150 人の同時ワーカーで 10 秒以上、できるだけ多くのリクエストを行うことによって実行されました。負荷生成は、Rust および Tokio ベースの HTTP 負荷テスト ツールである oha を使用して実行されました。

話はこれくらいにして、数字を見てみましょう!

1 秒あたりのリクエスト数: 型検証を使用すると、Encore.ts は ElysiaJS および Hono より 3 倍高速になります

Encore.ts — faster than ElysiaJS & Hono

(GitHub でベンチマーク コードを確認してください。)

パフォーマンスは別として、Encore.ts は Node.js との 100% の互換性を維持しながらこれを実現します。

仕組み: 外れ値の設計上の決定

どのようにしてこれが可能ですか?テストの結果、パフォーマンスの 3 つの主要な原因が特定されました。これらはすべて、Encore.ts が内部でどのように動作するかに関係しています。

1. Encore.ts はマルチスレッドであり、Rust ランタイムを利用しています

Node.js は、シングルスレッドのイベント ループを使用して JavaScript コードを実行します。シングルスレッドの性質にもかかわらず、これはノンブロッキング I/O 操作を使用し、基盤となる V8 JavaScript エンジン (Chrome にも搭載) が非常に最適化されているため、実際には非常にスケーラブルです。

しかし、シングルスレッドのイベント ループよりも高速なものがあることをご存知ですか?マルチスレッドのもの。

Encore.ts は 2 つの部分で構成されています:

  1. Encore.ts を使用してバックエンドを作成するときに使用する TypeScript SDK。

  2. Rust で書かれたマルチスレッドの非同期イベント ループを備えた高性能ランタイム (Tokio と Hyper を使用)。

Encore ランタイムは、受信した HTTP リクエストの受け入れや処理など、すべての I/O を処理します。これは、基盤となるハードウェアがサポートする限り多くのスレッドを利用する、完全に独立したイベント ループとして実行されます。

リクエストが完全に処理されデコードされると、Node.js イベント ループに渡され、API ハンドラーから応答を取得してクライアントに書き戻されます。

(先に言っておきます: はい、イベント ループにイベント ループを入れたので、イベント ループ中にイベント ループを行うことができます。)

Encore.ts — faster than ElysiaJS & Hono

2. Encore.ts はリクエスト スキーマを事前計算します

Encore.ts は、名前が示すように、TypeScript 用にゼロから設計されています。ただし、実際に TypeScript を実行することはできません。まず、すべての型情報を削除して JavaScript にコンパイルする必要があります。これは、実行時の型安全性の達成がはるかに難しく、受信リクエストの検証などが困難になることを意味し、代わりに実行時に API スキーマを定義するための Zod のようなソリューションが普及しています。

Encore.ts の動作が異なります。 Encore では、ネイティブ TypeScript タイプを使用してタイプセーフな API を定義します:

import { api } from "encore.dev/api";

interface BlogPost {
    id:    number;
    title: string;
    body:  string;
    likes: number;
}

export const getBlogPost = api(
    { method: "GET", path: "/blog/:id", expose: true },
    async ({ id }: { id: number }) => Promise {
        // ...
    },
);

Encore.ts はソース コードを解析して、HTTP ヘッダー、クエリ パラメーターなどを含む、各 API エンドポイントが予期するリクエストとレスポンスのスキーマを理解します。その後、スキーマが処理され、最適化され、Protobuf ファイルとして保存されます。

Encore ランタイムは起動時に、この Protobuf ファイルを読み取り、各 API エンドポイントが期待する正確な型定義を使用して、各 API エンドポイントに最適化されたリクエスト デコーダーとレスポンス エンコーダーを事前計算します。実際、Encore.ts はリクエストの検証も Rust で直接処理し、無効なリクエストが JS 層に触れる必要さえないことを保証し、多くのサービス拒否攻撃を軽減します。

Encore によるリクエスト スキーマの理解は、パフォーマンスの観点からも有益であることが証明されています。 Deno や Bun などの JavaScript ランタイムは、Encore の Rust ベースのランタイムと同様のアーキテクチャを使用します (実際、Deno も Rust Tokio Hyper を使用します)。ただし、Encore はリクエスト スキーマを理解していません。その結果、実行のために未処理の HTTP リクエストをシングルスレッド JavaScript エンジンに引き渡す必要があります。

一方、

Encore.ts は Rust 内でより多くのリクエスト処理を処理し、デコードされたリクエスト オブジェクトのみを渡します。マルチスレッド Rust でより多くのリクエスト ライフサイクルを処理することで、JavaScript イベント ループが解放され、HTTP リクエストを解析する代わりにアプリケーション ビジネス ロジックの実行に集中できるようになり、パフォーマンスがさらに向上します。

3. Encore.ts はインフラストラクチャと統合します

注意深い読者は傾向に気づいたかもしれません。パフォーマンスの鍵は、シングルスレッドの JavaScript イベント ループからできるだけ多くの作業をオフロードすることです。

Encore.ts がリクエスト/レスポンスのライフサイクルの大部分を Rust にオフロードする方法についてはすでに見てきました。それで、これ以上何をする必要があるでしょうか?

そうですね、バックエンド アプリケーションはサンドイッチのようなものです。受信リクエストを処理する無難な最上位層があります。中央にはおいしいトッピング (つまり、もちろんビジネス ロジック) があります。一番下には、データベースにクエリを実行したり、他の API エンドポイントを呼び出したりする、無愛想なデータ アクセス レイヤーがあります。

ビジネス ロジックについては多くのことはできません。結局のところ、それを TypeScript で書きたいのです。 — しかし、すべてのデータ アクセス操作が JS イベント ループを占有することにはあまり意味がありません。これらを Rust に移行すると、イベント ループがさらに解放され、アプリケーション コードの実行に集中できるようになります。

それが私たちがやったことです。

Encore.ts を使用すると、ソース コードでインフラストラクチャ リソースを直接宣言できます。

たとえば、Pub/Sub トピックを定義するには:

import { Topic } from "encore.dev/pubsub";

interface UserSignupEvent {
    userID: string;
    email:  string;
}

export const UserSignups = new Topic("user-signups", {
    deliveryGuarantee: "at-least-once",
});

// To publish:
await UserSignups.publish({ userID: "123", email: "[email protected]" });

「では、どの Pub/Sub テクノロジーが使用されているのでしょうか?」
— 全部です!

Encore Rust ランタイムには、AWS SQS SNS、GCP Pub/Sub、NSQ などの最も一般的な Pub/Sub テクノロジーの実装が含まれており、さらに多くの実装が計画されています (Kafka、NATS、Azure Service Bus など)。アプリケーションの起動時にランタイム構成でリソースごとに実装を指定することも、Encore の Cloud DevOps 自動化に処理させることもできます。

Encore.ts には、Pub/Sub 以外にも、PostgreSQL データベース、Secret、Cron ジョブなどのインフラストラクチャ統合が含まれています。

これらのインフラストラクチャ統合はすべて Encore.ts Rust ランタイムに実装されています。

これは、.publish() を呼び出すとすぐにペイロードが Rust に渡され、Rust がメッセージのパブリッシュを処理し、必要に応じて再試行するなどの処理を行います。同じことがデータベース クエリ、Pub/Sub メッセージのサブスクライブなどにも当てはまります。

最終結果として、Encore.ts を使用すると、事実上すべての非ビジネス ロジックが JS イベント ループからオフロードされます。

Encore.ts — faster than ElysiaJS & Hono

要するに、Encore.ts を使用すると、真のマルチスレッド バックエンドを「無料」で入手できると同時に、すべてのビジネス ロジックを TypeScript で記述することができます。

結論

このパフォーマンスが重要かどうかは、ユースケースによって異なります。小さな趣味のプロジェクトを構築している場合、それは主に学術的なものになります。しかし、本番環境のバックエンドをクラウドに移行する場合、かなり大きな影響を与える可能性があります。

レイテンシーの短縮はユーザー エクスペリエンスに直接影響します。当たり前のことを言うと、バックエンドが高速になるということは、フロントエンドがよりスムーズになることを意味し、それはユーザーの満足度を高めることを意味します。

スループットが高いということは、より少ないサーバーで同じ数のユーザーにサービスを提供できることを意味し、これはクラウド料金の削減に直接対応します。または、逆に、同じ数のサーバーでより多くのユーザーにサービスを提供できるため、パフォーマンスのボトルネックに遭遇することなくさらに拡張できます。

私たちは偏見を持っていますが、Encore は TypeScript で高性能のバックエンドを構築するための非常に優れた、世界最高のソリューションを提供すると考えています。高速でタイプセーフで、Node.js エコシステム全体と互換性があります。

すべてオープンソースなので、コードをチェックアウトして GitHub に貢献できます。

または、試してみて、ご意見をお聞かせください!

リリースステートメント この記事は次の場所に転載されています: https://dev.to/encore/encorets-3x-faster-than-elysiajs-hono-48hj?1 侵害がある場合は、[email protected] に連絡して削除してください。
最新のチュートリアル もっと>
  • バッファ: Node.js
    バッファ: Node.js
    Node.js のバッファーの簡単なガイド Node.js の A Buffer は、生のバイナリ データを処理するために使用されます。これは、ストリーム、ファイル、またはネットワーク データを操作するときに役立ちます。 バッファの作成方法 文字列から: co...
    プログラミング 2024 年 11 月 5 日に公開
  • Node.js でのバージョン管理をマスターする
    Node.js でのバージョン管理をマスターする
    開発者として、私たちは異なる Node.js バージョンを必要とするプロジェクトに頻繁に遭遇します。このシナリオは、Node.js プロジェクトに定期的に関与していない新人開発者と経験豊富な開発者の両方にとって落とし穴です。各プロジェクトに正しい Node.js バージョンが使用されていることを確認...
    プログラミング 2024 年 11 月 5 日に公開
  • トラブルシューティングのために Go バイナリに Git リビジョン情報を埋め込む方法
    トラブルシューティングのために Go バイナリに Git リビジョン情報を埋め込む方法
    Go バイナリでの Git リビジョンの決定コードをデプロイするとき、バイナリをビルド元の Git リビジョンに関連付けると便利です。トラブルシューティングの目的。ただし、リビジョン番号を使用してソース コードを直接更新することは、ソースが変更されるため現実的ではありません。解決策: ビルド フラグ...
    プログラミング 2024 年 11 月 5 日に公開
  • 一般的な HTML タグ: 視点
    一般的な HTML タグ: 視点
    HTML (HyperText Markup Language) は Web 開発の基礎を形成し、インターネット上のすべての Web ページの構造として機能します。 2024 年には、最も一般的な HTML タグとその高度な使用法を理解することで、開発者はより効率的でアクセスしやすく、視覚的に魅力的...
    プログラミング 2024 年 11 月 5 日に公開
  • CSSメディアクエリ
    CSSメディアクエリ
    Web サイトがさまざまなデバイス間でシームレスに機能することを保証することが、これまで以上に重要になっています。ユーザーがデスクトップ、ラップトップ、タブレット、スマートフォンから Web サイトにアクセスするようになったため、レスポンシブ デザインが必須となっています。レスポンシブ デザインの中...
    プログラミング 2024 年 11 月 5 日に公開
  • JavaScript でのホイスティングを理解する: 包括的なガイド
    JavaScript でのホイスティングを理解する: 包括的なガイド
    JavaScript でのホイスティング ホイストは、変数と関数の宣言が、含まれるスコープ (グローバル スコープまたは関数スコープ) の先頭に移動 (または「ホイスト」) される動作です。コードが実行されます。これは、コード内で実際に宣言される前に変数や関数を使用できることを意味...
    プログラミング 2024 年 11 月 5 日に公開
  • Stripe を単一製品の Django Python ショップに統合する
    Stripe を単一製品の Django Python ショップに統合する
    In the first part of this series, we created a Django online shop with htmx. In this second part, we'll handle orders using Stripe. What We'll...
    プログラミング 2024 年 11 月 5 日に公開
  • Laravel でキューに入れられたジョブをテストするためのヒント
    Laravel でキューに入れられたジョブをテストするためのヒント
    Laravel アプリケーションを使用する場合、コマンドが負荷の高いタスクを実行する必要があるシナリオに遭遇するのが一般的です。メインプロセスのブロックを避けるために、キューで処理できるジョブにタスクをオフロードすることを決定することもできます。 例を見てみましょう。コマンド app:import-...
    プログラミング 2024 年 11 月 5 日に公開
  • 人間レベルの自然言語理解 (NLU) システムを作成する方法
    人間レベルの自然言語理解 (NLU) システムを作成する方法
    Scope: Creating an NLU system that fully understands and processes human languages in a wide range of contexts, from conversations to literature. ...
    プログラミング 2024 年 11 月 5 日に公開
  • JSTL を使用して HashMap 内で ArrayList を反復するにはどうすればよいですか?
    JSTL を使用して HashMap 内で ArrayList を反復するにはどうすればよいですか?
    JSTL を使用した HashMap 内の ArrayList の反復Web 開発では、JSTL (JavaServer Pages Standard Tag Library) は、JSP での一般的なタスクを簡素化するためのタグのセットを提供します ( Javaサーバーページ)。そのようなタスクの...
    プログラミング 2024 年 11 月 5 日に公開
  • Encore.ts — ElysiaJS や Hono よりも高速
    Encore.ts — ElysiaJS や Hono よりも高速
    数か月前、私たちは TypeScript 用のオープンソース バックエンド フレームワークである Encore.ts をリリースしました。 すでに多くのフレームワークが存在するため、私たちが行った珍しい設計上の決定のいくつかと、それがどのようにして驚くべきパフォーマンス数値につながるのかを共有したい...
    プログラミング 2024 年 11 月 5 日に公開
  • + を使用した文字列連結が文字列リテラルで失敗するのはなぜですか?
    + を使用した文字列連結が文字列リテラルで失敗するのはなぜですか?
    文字列リテラルと文字列の連結C では、演算子を使用して文字列と文字列リテラルを連結できます。ただし、この機能には混乱を招く可能性のある制限があります。質問の中で、作成者は文字列リテラル「Hello」、「,world」、および「!」を連結しようとしています。 2つの異なる方法で。最初の例:const ...
    プログラミング 2024 年 11 月 5 日に公開
  • React の再レンダリング: 最適なパフォーマンスのためのベスト プラクティス
    React の再レンダリング: 最適なパフォーマンスのためのベスト プラクティス
    React の効率的なレンダリング メカニズムは、その人気の主な理由の 1 つです。ただし、アプリケーションが複雑になるにつれて、コンポーネントの再レンダリングの管理がパフォーマンスを最適化するために重要になります。 React のレンダリング動作を最適化し、不必要な再レンダリングを回避するためのベ...
    プログラミング 2024 年 11 月 5 日に公開
  • 条件付き列の作成を実現する方法: Pandas DataFrame で If-Elif-Else を探索する?
    条件付き列の作成を実現する方法: Pandas DataFrame で If-Elif-Else を探索する?
    条件付き列の作成: Pandas の If-Elif-Else指定された問題では、新しい列を DataFrame に追加することが求められます一連の条件付き基準に基づいて決定されます。課題は、コードの効率性と可読性を維持しながらこれらの条件を実装することにあります。関数アプリケーションを使用したソリ...
    プログラミング 2024 年 11 月 5 日に公開
  • 秋さんのご紹介です!
    秋さんのご紹介です!
    Qiu のリリースを発表できることを嬉しく思います。これは、生の SQL を再び楽しくするために設計された、実用的な SQL クエリ ランナーです。正直に言うと、ORM にはその役割がありますが、単純な SQL を書きたいだけの場合は、少し圧倒されてしまう可能性があります。私は生の SQL クエリ...
    プログラミング 2024 年 11 月 5 日に公開

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3