NestJS开发启动极其缓慢

23

我的应用在开发环境下启动相当缓慢,我在各个地方设置了一些调试日志,以查看是什么花费了如此多的时间。结果发现,我的main.ts文件实际上需要将近9分钟的时间才能导入app.module

import { performance } from 'perf_hooks';
const startTime = performance.now();

import { Log } from 'api/common/util/logger/log';
Log.log.info(`┌────────────────────────────────────────────────────────────┐`);
Log.log.info(`│    Starting: ${new Date().toISOString()}                      │`);
Log.log.info(`└────────────────────────────────────────────────────────────┘`);

// From here -------------------->
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import 'reflect-metadata';
import { existsSync, mkdirSync, writeFile } from 'fs';
import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as helmet from 'helmet';
import * as morgan from 'morgan';
import * as morganBody from 'morgan-body';
// <------ to here, imports fly in as expected.

// Theese take a bit longer, but not enormously
import { Config } from './api/common/config';
import { HttpExceptionFilter } from './api/common/filters/http-exception.filter';
import { LogService } from 'api/common/util/logger/log.service';

// This one takes up the most time on startup (several minutes)
import { AppModule } from './api/app.module';
Log.log.debug(` * imports done in ${(performance.now() - startTime).toFixed(3)}ms`);
Log.log.debug(` * Memory: ${readMem()}`);

function readMem() {
  const mem = process.memoryUsage();
  const convert = { Kb: n => (n / 1024), Mb: n => convert.Kb(n) / 1024 };
  const toHuman = (n, t) => `${convert[t](n).toFixed(2)}${t}`;
  return `Used ${toHuman(mem.heapUsed, 'Mb')} of ${toHuman(mem.heapTotal, 'Mb')} - RSS: ${toHuman(mem.rss, 'Mb')}`;
}

输出

生产启动:

$ node dist/main.js
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │    Starting: 2019-01-29T13:06:13.751Z                                    │
info: │      Memory: Used 6.54Mb of 11.70Mb - RSS: 25.33Mb                       │
info: │     Runtime: js                                                          │
info: └──────────────────────────────────────────────────────────────────────────┘
debug:  * imports done in 6862.350ms
debug:  * Memory: Used 87.99Mb of 113.76Mb - RSS: 133.58Mb
info: Nest application successfully started
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │             Memory: Used 93.71Mb of 122.52Mb - RSS: 144.20Mb             │
info: │             Launch: 2019-01-29T13:06:25.377Z                             │
info: │      Time to start: 11991.049ms                                          │
info: │     Bootstrap time: 5124.189ms                                           │
info: └──────────────────────────────────────────────────────────────────────────┘

开发初创公司:

$ ts-node -r tsconfig-paths/register src/main.ts
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │    Starting: 2019-01-29T13:08:06.914Z                                    │
info: │      Memory: Used 157.76Mb of 193.62Mb - RSS: 209.77Mb                   │
info: │     Runtime: ts                                                          │
info: └──────────────────────────────────────────────────────────────────────────┘
debug:  * imports done in 471159.063ms
debug:  * Memory: Used 297.45Mb of 385.35Mb - RSS: 408.90Mb
info: Nest application successfully started
info: ┌──────────────────────────────────────────────────────────────────────────┐
info: │             Memory: Used 216.64Mb of 383.35Mb - RSS: 409.11Mb            │
info: │             Launch: 2019-01-29T13:16:05.521Z                             │
info: │      Time to start: 483228.325ms                                         │
info: │     Bootstrap time: 12042.239ms                                          │
info: └──────────────────────────────────────────────────────────────────────────┘

是的,我使用ts-node开始了这个项目,但这是NestJS在开发和调试时推荐的。

问题

如何优化启动时间,使得后端每次进行微小更改都不需要等待10分钟?我本来就很难集中精力,这样做更加没帮助。

我的模块太多了吗?如果我将它们合并,会有所帮助吗?我有大约15个DB实体模型,每个模型都包含在自己的基于graphql的模块中,以提高可读性,但其中许多模型都存在由forwardRef()注入解决的循环依赖关系。这可能是一个问题吗?

我尽量少使用第三方库,以避免node_modules地狱。我在我的模块中导入的要么是我的代码,要么是NestJS框架的东西。当然,我不知道有多少隐式依赖项被加载了,但是我携带的库数量是否会影响启动性能呢?如果会的话,我该如何监控堆栈上的内容以及每个脚本在评估时消耗的内存/CPU量?我是否可以预编译其中的一些内容以增加启动速度?

当我在生产环境下以编译后的Javascript运行时,就没有这个问题。


不确定问题出在哪里,但可能受CPU性能的影响。例如,低规格的加载速度比高端规格慢。我正在加载40多个模块,需要141349毫秒。而我的同事使用更好的CPU规格,几乎可以将我的加载时间缩短一半。 - Mukyuu
1
我不确定,但我认为NodeJS受到内存保留的限制。如此所述在这里。我认为这个可能会有所帮助。 - Mukyuu
你有解决这个问题的方法吗?我也遇到了同样的问题。 - Fabian Vilers
不,我的解决方法是在一个终端中运行tsc --watch,并在每次进行更改时重新启动node ./dist/main.js。这可能可以使用nodemon更好地完成,但我无法让它与vscode一起工作。 - Øystein Amundsen
我遇到了同样的问题,但是没有任何建议起作用。我正在使用ver nest/core、nestjs/common和nestjs/graphql-express ver 6.8.5以及nestjs/grapql 6.5.3。如果我不管它,在大约4个小时后(是的),它将完成启动,并且其中一个模块需要所有时间来启动……我还使用最新的kit与tsc-watch。 - MichaelE
显示剩余3条评论
8个回答

6

这个解决方案导致服务器重新启动非常缓慢。 - Siner

5

一种选择是使用 tsc-watch 而非 ts-node 和 nodemon。您可以按照以下方式在 start:dev 中设置启动命令:

{
  //this is assuming you're building to the dist folder
  ...
  "start:dev": "tsc-watch --onSuccess \"node dist/main.js\" --onFailure \"echo 
  There was a problem with the build!\" -p tsconfig.json" 
  ...
}

在我的经验中,使用ts-node和路由注册时遇到了太多的问题,并且加载时间太长,使用tsc-watch可以获得项目的新构建,仅重新构建更改的文件。这样你也可以在开发过程中测试tsc的工作。
我还使用tsconfig-bootstrap命令导入我自定义的路由(在我的tsconfig中定义),并将其添加到启动命令中,例如:node -r path/to/my/script.js dist/main.js
希望这能对你有所帮助!

2
如果有人遇到这个问题,我们有一个拥有40个模块的 Nest API,在使用node v12时启动时间大约为2-3分钟,而在使用node v14+时启动时间在5-10秒之间。我建议您在本地开发时使用NVM,并尝试使用更高版本的node(如果包兼容的话)。

1
我在升级到nest@8.0.0并开始使用node v16后遇到了这个问题。在我降级nodejs版本后,问题解决了。
编辑:该问题与pg模块有关。它默默地失败了。更新到pg@latest后,NestJs正常启动。

1
  • 请检查您的服务器是否连接到远程数据库,如果是这种情况,可能会导致您的服务器运行时间变慢。
  • 如果您正在使用mongoDB,请检查您正在使用的mongoose版本
  • 对于MYSQL,请使用“mysql workbench”而不是xampp(我个人通过这样做来解决了问题)

PS:在大多数情况下,远程连接将影响您的服务器,使其变慢


0

只是加上这个,以防其他人可能有相同的原因,我的问题是由于导入grpc客户端,两者都没有足够具体地指定要包含哪些proto,并且在太多不同的位置。

我们的protos结构非常大,所以grpc加载器加载速度非常慢,这导致巢穴需要几分钟才能启动。

因此,请确保您仅在配置的protoPath中直接使用所需的服务。我认为includeDirs选项并不重要,因此只需protoPath。


0
一种逻辑的解决方案,可以解决问题并使其正常工作,就是从应用程序模块中取消注释当前未使用的模块。

@Module({
 imports: [
   TypeOrmModule.forRoot(defaultOptions),
   // Commented for faster reloads 
   // NotUsingModule1
   // NotUsingModule2
   UsingModule1
 ],
 controllers: [AppController],
 providers: [AppService],
})
export class AppModule { }

如果使用关系型数据库,请确保不将日志记录设置为true,也不要将dropSchema设置为true。

  • 在某些情况下,您可能会遇到实体无法正确形成关系的问题,请将dropSchema设置为true,它将从数据库中清除所有实体。但是请注意,在生产环境中不要这样做。您已经被警告了。
export const defaultOptions = {
    type: "postgres",
    port: 5432,
    username: "postgres",
    password: "postgres",
    database: "awesome db",
    synchronize: true,
    // logging: true,
    // dropSchema: true,
    entities: ['dist/**/*.entity.js'],

-1

安装最新版本的@nestjs/cli,全局和本地都要安装:

$ npm install -g @nestjs/cli
$ cd  /some/project/root/folder
$ npm install -D @nestjs/cli

替换/确保您在package.json中定义了以下脚本

"build": "nest build",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",

确保您已经在使用 VS Code 自动附加功能 enter image description here

运行

npm run start:dev

这个如何确切地加速NestJS编译?对我来说似乎是默认设置。 - David Zwart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接