【问题标题】:NestJS startup unbelievably slow in developmentNestJS 启动开发速度慢得令人难以置信
【发布时间】:2019-06-22 09:58:59
【问题描述】:

我在开发环境中的应用程序在启动阶段非常缓慢。我在各个地方设置了一些调试日志,看看是什么占用了这么多时间,发现我的 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 运行时我没有这个问题。

【问题讨论】:

  • 我没有看到任何可疑的东西。可能您正在 nodemon 中运行一些预启动活动。这可能会导致一些问题。
  • 不确定是什么问题,但可能会受到 CPU 性能的影响。例如,较低规格的加载速度将比高端规格慢。我正在用 141349 毫秒加载 40 多个模块。虽然我的同事能够使用他们更好的 CPU 规格加载几乎一半的加载时间。
  • @klvenky 如果 nodemon 中有一些预启动活动,它们不会在编写应用程序的第一个输出时完成吗?直到我得到第一次打印,如上面的代码所示,我才开始测量。
  • @Mukyuu 是否像 Java 一样受制于内存/cpu 预留?我可以指定我允许进程消耗多少内存和 CPU(就像 Java 一样)?
  • CMIIW 但我相信 NodeJS 会受到内存预留的影响。如here 所述。我认为this 可能会有所帮助。

标签: node.js typescript nestjs ts-node


【解决方案1】:

尝试设置环境TS_NODE_TRANSPILE_ONLY=true

例如TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register src/main.ts

文档:https://github.com/TypeStrong/ts-node#cli-and-programmatic-options

它加快了我的应用启动速度

【讨论】:

  • 这个解决方案让服务器重启很慢
【解决方案2】:

一种选择是使用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 tscfonig.json" 
  ...
}

根据我的经验,我在ts-node 和注册路由方面遇到了太多问题,而且加载时间让我感到厌烦。使用tsc-watch,我得到了一个全新的项目版本,只重建了已更改的文件。这样,您还可以测试 tsc 在开发过程中是否有效。


我还使用 tsconfig-bootstrap 命令导入我的自定义路由(在我的 tsconfig 中定义)并使用node -r path/to/my/script.js dist/main.js 将其添加到我的启动命令中。

希望对你有所帮助!

【讨论】:

    【解决方案3】:

    升级到nest@8.0.0 并开始使用node v16 后我遇到了这个问题。在我降级nodejs版本后问题就消失了。

    编辑:问题与pg 模块有关。它无声无息地坠落。更新到pg@latestNestJs后正常启动。

    【讨论】:

      【解决方案4】:

      在全局和本地安装最新版本的@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 代码

      运行

      npm run start:dev
      

      【讨论】:

        【解决方案5】:

        一个合乎逻辑的解决方案和解决问题的方法是从应用模块中取消注释您当前未使用的模块。

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

        此外,如果使用 RDBMS,请确保登录未设置为 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'],
        

        【讨论】:

          【解决方案6】:

          只是添加这个以防其他人可能有同样的原因,我的问题是由于导入了 grpc 客户端,这两个客户端都不够具体,包括哪些 proto(s) 以及在太多不同的地方。

          我们的 protos 结构非常大,因此 grpc 加载器加载速度非常慢,导致 Nest 需要几分钟才能启动。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-12-05
            • 2016-12-10
            • 1970-01-01
            • 2013-11-21
            • 2014-12-28
            • 2023-03-13
            • 1970-01-01
            • 2013-01-06
            相关资源
            最近更新 更多