」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > Encore.ts — 比 ElysiaJS 和 Hono 更快

Encore.ts — 比 ElysiaJS 和 Hono 更快

發佈於2024-11-05
瀏覽:740

几个月前,我们发布了 Encore.ts — TypeScript 的开源后端框架。

由于已经有很多框架,我们想分享我们做出的一些不常见的设计决策以及它们如何带来卓越的性能数据。

性能基准

我们之前发布的基准测试显示 Encore.ts 比 Express 快 9 倍,比 Fastify 快 2 倍。

这次我们将 Encore.ts 与 ElysiaJS 和 Hono 这两个现代高性能 TypeScript 框架进行了基准测试。

我们对带有和不带有模式验证的每个框架进行了基准测试,使用 TypeBox 与 ElsyiaJS 和 Hono 进行验证,因为它是这些框架原生支持的验证库。 (Encore.ts 有自己的内置类型验证,可以端到端工作。)

对于每个基准测试,我们选取​​五次运行中的最佳结果。每次运行都是通过 150 个并发工作线程发出尽可能多的请求来执行,时间超过 10 秒。负载生成是使用 oha 执行的,oha 是一个基于 Rust 和 Tokio 的 HTTP 负载测试工具。

废话不多说,让我们看看数字!

每秒请求数:使用类型验证时,Encore.ts 比 ElysiaJS 和 Hono 快 3 倍

Encore.ts — faster than ElysiaJS & Hono

(查看 GitHub 上的基准代码。)

除了性能之外,Encore.ts 还实现了这一点,同时保持了与 Node.js 100% 的兼容性

工作原理:异常设计决策

这怎么可能?通过我们的测试,我们确定了性能的三个主要来源,所有这些都与 Encore.ts 的工作原理有关。

1. Encore.ts 是多线程的,由 Rust 运行时提供支持

Node.js 使用单线程事件循环运行 JavaScript 代码。尽管其具有单线程性质,但实际上它具有相当大的可扩展性,因为它使用非阻塞 I/O 操作,并且底层 V8 JavaScript 引擎(也为 Chrome 提供支持)经过了极其优化。

但是您知道什么比单线程事件循环更快吗?多线程。

Encore.ts由两部分组成:

  1. 使用 Encore.ts 编写后端时使用的 TypeScript SDK。

  2. 高性能运行时,具有用 Rust 编写的多线程异步事件循环(使用 Tokio 和 Hyper)。

Encore Runtime 处理所有 I/O,例如接受和处理传入的 HTTP 请求。它作为一个完全独立的事件循环运行,利用底层硬件支持的尽可能多的线程。

一旦请求被完全处理和解码,它就会被移交给 Node.js 事件循环,然后从 API 处理程序获取响应并将其写回客户端。

(在你说之前:是的,我们在你的事件循环中放置了一个事件循环,这样你就可以在事件循环时进行事件循环。)

Encore.ts — faster than ElysiaJS & Hono

2. Encore.ts 预先计算请求模式

Encore.ts,顾名思义,是专为 TypeScript 设计的。但你实际上无法运行 TypeScript:它首先必须通过剥离所有类型信息来编译为 JavaScript。这意味着运行时类型安全更难实现,这使得验证传入请求之类的事情变得困难,导致像 Zod 这样的解决方案在运行时定义 API 模式变得流行。

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 然后解析源代码以了解每个 API 端点期望的请求和响应架构,包括 HTTP 标头、查询参数等。然后对模式进行处理、优化并存储为 Protobuf 文件。

当 Encore Runtime 启动时,它会读取此 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 运行时包括最常见的 Pub/Sub 技术的实现,包括 AWS SQS SNS、GCP Pub/Sub 和 NSQ,以及更多计划中的技术(Kafka、NATS、Azure 服务总线等)。您可以在应用程序启动时在运行时配置中按资源指定实现,或者让 Encore 的 Cloud DevOps 自动化为您处理。

除了 Pub/Sub 之外,Encore.ts 还包括 PostgreSQL 数据库、Secrets、Cron Jobs 等的基础设施集成。

所有这些基础设施集成都在 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 中的 Buffer 用於處理原始二進位數據,這在處理流、文件或網路數據時非常有用。 如何建立緩衝區 來自字串: const buf = Buffer.from('Hello'); 分配特定大小的Buffer...
    程式設計 發佈於2024-11-05
  • 掌握 Node.js 中的版本管理
    掌握 Node.js 中的版本管理
    作為開發者,我們經常遇到需要不同 Node.js 版本的專案。對於可能不經常參與 Node.js 專案的新手和經驗豐富的開發人員來說,這種情況都是一個陷阱:確保每個專案使用正確的 Node.js 版本。 在安裝依賴項並執行專案之前,驗證您的 Node.js 版本是否符合或至少相容專案的要求至關重要...
    程式設計 發佈於2024-11-05
  • 如何在 Go 二進位檔案中嵌入 Git 修訂資訊以進行故障排除?
    如何在 Go 二進位檔案中嵌入 Git 修訂資訊以進行故障排除?
    確定Go 二進位檔案中的Git 修訂版部署程式碼時,將二進位檔案與建置它們的git 修訂版關聯起來會很有幫助排除故障的目的。然而,直接使用修訂號更新原始程式碼是不可行的,因為它會改變原始程式碼。 解決方案:利用建造標誌解決此挑戰的方法包括利用建造標誌。透過使用建置標誌在主套件中設定當前 git 修訂...
    程式設計 發佈於2024-11-05
  • 常見 HTML 標籤:視角
    常見 HTML 標籤:視角
    HTML(超文本標記語言)構成了 Web 開發的基礎,是互聯網上每個網頁的結構。透過了解最常見的 HTML 標籤及其高級用途,到 2024 年,開發人員可以創建更有效率、更易於存取且更具視覺吸引力的網頁。在這篇文章中,我們將探討這些 HTML 標籤及其最高級的用例,以協助您提升 Web 開發技能。 ...
    程式設計 發佈於2024-11-05
  • CSS 媒體查詢
    CSS 媒體查詢
    確保網站在各種裝置上無縫運作比以往任何時候都更加重要。隨著用戶透過桌上型電腦、筆記型電腦、平板電腦和智慧型手機造訪網站,響應式設計已成為必要。響應式設計的核心在於媒體查詢,這是一項強大的 CSS 功能,可讓開發人員根據使用者裝置的特徵應用不同的樣式。在本文中,我們將探討什麼是媒體查詢、它們如何運作以...
    程式設計 發佈於2024-11-05
  • 了解 JavaScript 中的提升:綜合指南
    了解 JavaScript 中的提升:綜合指南
    JavaScript 中的提升 提升是一種行為,其中變數和函數聲明在先前被移動(或「提升」)到其包含範圍(全域範圍或函數範圍)的頂部程式碼被執行。這意味著您可以在程式碼中實際聲明變數和函數之前使用它們。 變數提升 變數 用 var 宣告的變數被提升...
    程式設計 發佈於2024-11-05
  • 將 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-05
  • 在 Laravel 測試排隊作業的技巧
    在 Laravel 測試排隊作業的技巧
    使用 Laravel 應用程式時,經常會遇到命令需要執行昂貴任務的情況。為了避免阻塞主進程,您可能決定將任務卸載到可以由佇列處理的作業。 讓我們來看一個例子。想像一下指令 app:import-users 需要讀取一個大的 CSV 檔案並為每個條目建立一個使用者。該命令可能如下所示: /* Imp...
    程式設計 發佈於2024-11-05
  • 如何創建人類層級的自然語言理解 (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-05
  • 如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    使用JSTL 迭代HashMap 中的ArrayList在Web 開發中,JSTL(JavaServer Pages 標準標記庫)提供了一組標記來簡化JSP 中的常見任務( Java 伺服器頁面)。其中一項任務是迭代資料結構。 要迭代 HashMap 及其中包含的 ArrayList,可以使用 JS...
    程式設計 發佈於2024-11-05
  • Encore.ts — 比 ElysiaJS 和 Hono 更快
    Encore.ts — 比 ElysiaJS 和 Hono 更快
    几个月前,我们发布了 Encore.ts — TypeScript 的开源后端框架。 由于已经有很多框架,我们想分享我们做出的一些不常见的设计决策以及它们如何带来卓越的性能数据。 性能基准 我们之前发布的基准测试显示 Encore.ts 比 Express 快 9 倍,比 Fasti...
    程式設計 發佈於2024-11-05
  • 為什麼使用 + 對字串文字進行字串連接失敗?
    為什麼使用 + 對字串文字進行字串連接失敗?
    連接字串文字與字串在 C 中,運算子可用於連接字串和字串文字。但是,此功能存在限制,可能會導致混亂。 在問題中,作者嘗試連接字串文字「Hello」、「,world」和「!」以兩種不同的方式。第一個例子:const string hello = "Hello"; const str...
    程式設計 發佈於2024-11-05
  • React 重新渲染:最佳效能的最佳實踐
    React 重新渲染:最佳效能的最佳實踐
    React高效率的渲染機制是其受歡迎的關鍵原因之一。然而,隨著應用程式複雜性的增加,管理元件重新渲染對於最佳化效能變得至關重要。讓我們探索優化 React 渲染行為並避免不必要的重新渲染的最佳實踐。 1. 使用 React.memo() 作為函數式元件 React.memo() 是...
    程式設計 發佈於2024-11-05
  • 如何實作條件列建立:探索 Pandas DataFrame 中的 If-Elif-Else?
    如何實作條件列建立:探索 Pandas DataFrame 中的 If-Elif-Else?
    Creating a Conditional Column: If-Elif-Else in Pandas給定的問題要求將新列新增至DataFrame 中基於一系列條件標準。挑戰在於在實現這些條件的同時保持程式碼效率和可讀性。 使用函數應用程式的解決方案一種方法涉及創建一個將每一行映射到所需結果的函...
    程式設計 發佈於2024-11-05
  • 介紹邱!
    介紹邱!
    我很高興地宣布發布 Qiu – 一個嚴肅的 SQL 查詢運行器,旨在讓原始 SQL 再次變得有趣。老實說,ORM 有其用武之地,但當您只想編寫簡單的 SQL 時,它們可能會有點不知所措。我一直很喜歡寫原始 SQL 查詢,但我意識到我需要練習——大量的練習。這就是Qiu發揮作用的地方。 有了 Qiu...
    程式設計 發佈於2024-11-05

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3