详解Node.js 应用高 CPU 占用率分析方法

作者:后端茶话时间:2026-10-25 22:28:24浏览:386

本文详细介绍 Node.js 应用高 CPU 占用率的排查方法,涵盖本地调试与生产环境数据采集。通过 Chrome DevTools 和 Node.js 内置 inspector 模块,结合 NestJS 示例代码,演示如何按需生成 CPU Profile,帮助开发者高效定位性能瓶颈。

在本地环境中运行 Node.js 应用程序

我们在本地启动 Node.js 应用,通过传递 --inspect 参数来运行程序,随后执行负载测试,并在 Chrome 浏览器中访问 chrome://inspect 页面:

在本地环境中运行 Node.js 应用程序

点击应用下方的 inspect 按钮,随即启动 CPU 占用率分析:

在本地环境中运行 Node.js 应用程序

经过一段时间的等待,即可查看到 CPU profile 的分析结果:

在本地环境中运行 Node.js 应用程序

如何获取生产环境中 Node.js 应用的性能数据

通常情况下,若性能问题仅在生产环境中复现,分析难度极大,因为必须保持完全一致的环境配置、数据库及缓存等数据。此类性能瓶颈可能仅影响拥有特定数据的特定用户群体。

在生产环境中开启调试模式并非良策,因为调试模式下的 Node.js 进程会占用更多系统资源,且存在安全隐患。

然而,存在一种更优方案,即利用检查器模块 nodejs.org/api/inspect… 按需获取配置文件。该模块为 Node.js 内置功能,开发者无需安装额外依赖,但推荐使用 inspector-api。

这是一个支持 Promise 的简易封装器。接下来,我们将创建一个用于记录 CPU 配置文件的接口端点。

以下示例基于 NestJS 框架编写,其他框架的实现方式大致相同:

具体代码实现如下:

import { Controller, Post } from '@nestjs/common'
import { promisify } from 'util'
import Inspector from 'inspector-api'
const profileRecordTime = 10000
@Controller('/profile')
export class ProfileController {
  @Post('/cpu')
  async cpu() {
    // don't wait till recording is finished
    setImmediate(async () => {
      // cpu profile will be saved in temp dir
      const inspector = new Inspector({ storage: { type: 'fs' } })
      // enabling and starting profiling
      await inspector.profiler.enable()
      await inspector.profiler.start()
      // wait for 10 seconds and stop
      await promisify(setTimeout)(profileRecordTime)
      await inspector.profiler.stop()
      console.log('CPU profile has been written')
      await inspector.profiler.disable()
    })
    return true
  }
}

所有代码逻辑均被 setImmediate 包裹,因为我们无需等待录制过程结束。接下来使用 curl 命令进行测试:

curl -X POST http://127.0.0.1/profile/cpu

10 秒后,我们在 temp 文件夹中获取到了 CPU profile 的采集结果:

在本地环境中运行 Node.js 应用程序

若不希望将此功能暴露为 HTTP 端点,可将其封装在进程信号处理程序中,具体实现如下:

import { promisify } from 'util'
import Inspector from 'inspector-api'
const profileRecordTime = 10000
process.on('SIGUSR1', async () => {
  const inspector = new Inspector({ storage: { type: 'fs' } })
  await inspector.profiler.enable()
  await inspector.profiler.start()
  await promisify(setTimeout)(profileRecordTime)
  await inspector.profiler.stop()
  console.log('CPU profile has been written')
  await inspector.profiler.disable()
})
process.on('SIGUSR2', async () => {
  const inspector = new Inspector({ storage: { type: 'fs' } })
  await inspector.heap.enable()
  await inspector.heap.startSampling()
  await promisify(setTimeout)(profileRecordTime)
  await inspector.heap.stopSampling()
  console.log('CPU profile has been written')
  await inspector.heap.disable()
})

随后通过 kill 命令发送相应信号:

  • kill -USR1 ${pid} // for CPU
  • kill -USR2 ${pid} // for Heap

以上即为详解 Node.js 应用高 CPU 占用率分析方法的完整内容,如需了解更多关于 Node.js 应用高 CPU 占用率的资料,敬请查阅本站其他相关文章!

作者最新文章