[Nestia] 使用 fastify 使 NestJS 速度提高 30 倍
大纲
nestia
并将服务器性能fastify
提高NestJS
约 10 倍至 30 倍。
- 上一篇文章:更快、更轻松地提升 NestJS 服务器
- Github仓库:https://github.com/samchon/nestia
- 指南文档:https://nestia.io/docs
在上一篇文章中,我介绍了我的库nestia
,它使验证过程NestJS
更加轻松快捷。在介绍性能增强功能的文章中,我提到它nestia
可以将验证速度最高提升 20,000 倍(JSON 序列化速度提升 200 倍)。
顺便说一句,有些人这样问过我:
好的,
nestia
通过大幅提升验证和序列化速度,您的代码使 NestJS 服务器速度更快了。顺便问一下,服务器整体性能怎么样?我特别想知道nestia
同时连接数能增加多少。
nestia
整个服务器层面的性能如何?
今天,我终于找到了答案。答案是,nestia
(+ fastify
) 可以将NestJS
服务器可用性提高大约10 倍到 30 倍。我会向你展示我是如何测量的,并解释仅验证和 JSON 序列化就如何影响整个服务器的性能。
作为参考,您可以按照以下命令在您的计算机上运行基准测试程序。基准测试结束后,会在nestia/benchmark/results/{YOUR-CPU-NAME}
目录下生成一份报告。如果您将结果 PR 发送到我的代码库 ( https://github.com/samchon/nestia ),我将非常高兴并感激不尽。
git clone https://github.com/samchon/nestia
cd nestia/benchmark
npm install
npm start
验证
如何使用
import { TypedBody, TypedParam, TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
import { IBbsArticle } from "./IBbsArticle";
@Controller("bbs/articles")
export class BbsArticlesController {
@TypedRoute.Put(":id")
public async update(
@TypedParam("id", "uuid") id: string,
@TypedBody() input: IBbsArticle.IUpdate, // 20,000x faster validation
): Promise<void> {}
}
当您NestJS
使用开发后端服务器时nestia
,您只需使用@nestia.TypedBody()
像上面那样的装饰器函数就可以轻松验证请求正文数据。
作为参考,与class-validator
和class-transform
不同,NestJS
它们需要三重重复的模式定义,nestia
可以使用纯 TypeScript 类型。查看下面的代码片段,你就能理解如何nestia
轻松创建 DTO 模式定义。
//----
// NESTJS (class-validator + class-transform) REQUIRES
// TRIPLE DUPLICATED DEFINITION
//----
export class BbsArticle {
@ApiProperty({
type: () => AttachmentFile,
nullable: true,
isArray: true,
description: "List of attached files.",
})
@Type(() => AttachmentFile)
@IsArray()
@IsOptional()
@IsObject({ each: true })
@ValidateNested({ each: true })
files!: AttachmentFile[] | null;
}
//----
// BESIDES, NESTIA UNDERSTANDS PURE TYPESCRIPT TYPE
//----
export interface IBbsArticle {
files: IAttachmentFile[] | null;
}
个人表现
在 Intel i5-1135g7、Surface Pro 8上测量
在测量验证性能时,nestia
(nestia
利用typia.assert<T>()
函数)比默认class-validator
使用的速度最多快 20,000 倍。NestJS
您觉得如果将如此快的验证速度应用到整个服务器层面会怎样?由于请求体数据的验证只占整个后端服务器的一小部分,这种性能差异是否对整体服务器层面的影响不够大?或者说,2 万倍的差距是一个巨大的数值,因此会影响整个服务器的性能?
让我们看看下面的服务器基准图。
服务器性能
答案是整个服务器级别的性能受到严重影响。
当比较服务器整体并发连接数的性能时,nestia
可以将并发连接数提高约 10 倍NestJS
。如果采用fastify
,则性能差距将扩大至 25 倍。此外,采用fastify
仅能NestJS
提高约 1~2% 的性能。
我认为造成如此显著的差异有两个原因。
第一种是:验证在主线程中处理。众所周知,NodeJS 的优势在于其事件处理机制,这些事件由非阻塞 I/O 实现,并且都在后台运行。然而,请求体数据的验证是在主线程中处理的,因此如果此类验证逻辑运行缓慢,就会导致整个后端服务器宕机。
第二个原因,只是2 万倍的差距。虽然请求体数据验证在整个服务器流程框架内只是一项小工作,但如果性能差距达到 2 万倍,那将是巨大的差异。
考虑到主线程操作具有 20,000 倍的性能差距,上述基准测试结果是足够合理的。
参考
作为参考,请求体验证使用了长度为 100 的 Array 实例。如果将长度缩减为 10,性能提升会减半(约 60%)。反之,随着长度的增加,性能提升会显著提升。
// "IBox3D" SIMILAR DTOS ARE USED, WITH 100 LENGTH ARRAY
export interface IBox3D {
scale: IPoint3D;
position: IPoint3D;
rotate: IPoint3D;
pivot: IPoint3D;
}
export interface IPoint3D {
x: number;
y: number;
z: number;
}
JSON序列化
如何使用
import { TypedBody, TypedParam } from "@nestia/core";
import { Controller } from "@nestjs/common";
import typia from "typia";
import { IBbsArticle } from "./IBbsArticle";
@Controller("bbs/articles")
export class BbsArticlesController {
@TypedRoute.Get(":id") // 200x faster JSON serialization
public async at(
@TypedParam("id", "uuid") id: string
): Promise<IBbsArticle> {
return typia.random<IBbsArticle>();
}
}
当你NestJS
使用开发后端服务器时nestia
,你可以通过使用像上面那样的装饰器函数轻松提高 JSON 序列化速度@nestia.EncryptedRoute.${method}()
。
作为参考,与class-validator
和class-transform
不同,NestJS
它们需要三重重复的模式定义,nestia
可以使用纯 TypeScript 类型。查看下面的代码片段,你就能理解如何nestia
轻松创建 DTO 模式定义。
//----
// NESTJS (class-validator + class-transform) REQUIRES
// TRIPLE DUPLICATED DEFINITION
//----
export class BbsArticle {
@ApiProperty({
type: () => AttachmentFile,
nullable: true,
isArray: true,
description: "List of attached files.",
})
@Type(() => AttachmentFile)
@IsArray()
@IsOptional()
@IsObject({ each: true })
@ValidateNested({ each: true })
files!: AttachmentFile[] | null;
}
//----
// BESIDES, NESTIA UNDERSTANDS PURE TYPESCRIPT TYPE
//----
export interface IBbsArticle {
files: IAttachmentFile[] | null;
}
个人表现
你还记得吗?我曾经写过一篇关于我的另一个库的文章typia
,比较了typia
和之间的 JSON 序列化性能class-transformer
。在之前的基准测试中,typia
最多比 快 200 倍class-transformer
。
供参考,nestia
利用typia
,并NestJS
利用class-transformer
。
- 上一篇文章:我让 Express 比 Fastify 更快
- Github仓库:https://github.com/samchon/typia
- 指南文档:https://typia.io/docs
您觉得如果将如此快的 JSON 序列化速度应用到整个服务器层面会怎样?由于 JSON 序列化的性能提升远小于验证器的性能提升(200 倍 vs 20,000 倍),那么这种性能差异是否对整个服务器层面的影响不够大?或者,200 倍的差距会影响整个服务器的性能,因为 JSON 序列化的工作量比验证器更大?
让我们看看下面的服务器基准图。
服务器性能
答案是整个服务器级别的性能也会受到显著影响。
当比较服务器整体并发连接数的性能时,nestia
可以将并发连接数提高约 10 倍NestJS
。如果采用fastify
,则性能差距将扩大至 18 倍。此外,采用fastify
仅能NestJS
提升约 0~10% 的性能。
我认为造成如此显著的差异有两个原因。
第一个原因与验证情况相同。JSON 序列化在主线程中处理。众所周知,NodeJS 的优势在于非阻塞 I/O 所代表的事件,所有这些事件都在后台运行。然而,请求主体数据验证是在主线程中处理的,因此如果此类验证逻辑运行缓慢,就会导致整个后端服务器停止运行。
第二个原因是 JSON 序列化比验证更繁琐。因此,即使 JSON 序列化的性能提升不如验证(200 倍 vs 20,000 倍),但在整个服务器层面上,这仍然是显著的。
考虑到主线程操作和比验证更重的 JSON 序列化过程,上述基准测试结果是足够合理的。
综合绩效
import { TypedBody, TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
import { IBbsArticle } from "./IBbsArticle";
@Controller("bbs/articles")
export class BbsArticlesController {
@TypedRoute.Post()
public async store(
@TypedBody() input: IBbsArticle.IStore
): Promise<IBbsArticle> {
return {
...input,
id: "2b5e21d8-0e44-4482-bd3e-4540dee7f3d6",
created_at: "2023-04-23T12:04:54.168Z",
}
}
}
最后一个基准测试是关于复合性能的,它同时验证请求体数据和序列化 JSON 响应数据。正如nestia
之前所显示的显著性能差距一样,复合基准测试也显示出了显著的性能差距。
nestia
让我们看看下面的基准测试图,想象一下如果你在后端服务器中采用这种方法,性能会提升多少NestJS
。我想没有理由不使用它了nestia
。它速度更快,甚至更容易。
结论
nestia
显著提升NestJS
服务器性能- 如果适应
fastify
,nestia
性能将会提高更多 - 否则,
fastify
不适应nestia
,性能就不会提高 nestia
开发NestJS
后端服务器 时使用- 更快
- 更容易
- 甚至支持 SDK 生成
tRPC
文章来源:https://dev.to/samchon/nestia-make-nestjs-30x-faster-with-fastify-133l左边是服务器代码,右边是客户端(前端)代码