正在加载,请稍候…

Node.js 性能分析:发现并修复瓶颈

对 Node.js 应用进行性能分析和优化。学习使用 clinic.js 进行 CPU 分析、内存泄漏检测、事件循环监控以及修复常见性能问题。

Node.js 性能分析:发现并修复瓶颈

Node.js 性能分析

使用 clinic.js 进行 CPU 分析

# 安装 clinic.js
npm install -g clinic

# CPU 分析器(火焰图)
clinic flame -- node server.js

# Doctor(事件循环、内存、CPU 概览)
clinic doctor -- node server.js

# Bubbleprof(异步瓶颈)
clinic bubbleprof -- node server.js

Node.js 性能分析:发现并修复瓶颈 插图

内置 Node.js 分析器

# 启用分析启动
node --prof server.js

# 运行负载测试
npx autocannon http://localhost:3000/api/heavy -d 10

# 处理分析数据
node --prof-process isolate-0x*.log > profile.txt

# 查看火焰图
node --prof-process --preprocess isolate-0x*.log | flamebearer

Node.js 性能分析:发现并修复瓶颈 插图

内存泄漏检测

// 检测内存增长
const startMemory = process.memoryUsage();
setInterval(() => {
  const mem = process.memoryUsage();
  const heapGrowth = mem.heapUsed - startMemory.heapUsed;

  if (heapGrowth > 100 * 1024 * 1024) { // 100MB 增长
    console.warn('检测到潜在内存泄漏', {
      heapUsed: Math.round(mem.heapUsed / 1024 / 1024) + 'MB',
      heapTotal: Math.round(mem.heapTotal / 1024 / 1024) + 'MB',
      rss: Math.round(mem.rss / 1024 / 1024) + 'MB',
    });
  }
}, 30000);
# 使用 node-inspector 进行堆快照
node --inspect server.js
# 打开 Chrome DevTools -> Memory -> 获取堆快照
# 比较疑似泄漏前后的快照

# 编程方式使用 heapdump
npm install heapdump
import heapdump from 'heapdump';

process.on('SIGUSR2', () => {
  const filename = `/tmp/heapdump-${Date.now()}.heapsnapshot`;
  heapdump.writeSnapshot(filename, (err, filename) => {
    if (!err) console.log('堆快照已保存:', filename);
  });
});
// 触发: kill -SIGUSR2 <pid>

Node.js 性能分析:发现并修复瓶颈 插图

事件循环监控

import { monitorEventLoopDelay } from 'perf_hooks';

const h = monitorEventLoopDelay({ resolution: 20 });
h.enable();

setInterval(() => {
  const mean = h.mean / 1e6; // 转换为毫秒
  const p99 = h.percentile(99) / 1e6;

  if (p99 > 100) {
    console.warn(`事件循环延迟高: mean=${mean.toFixed(1)}ms, p99=${p99.toFixed(1)}ms`);
  }

  h.reset();
}, 5000);

常见性能问题

// 问题:同步操作阻塞事件循环
import fs from 'fs';

// 不好:阻塞事件循环
const data = fs.readFileSync('/large-file.json');

// 好:非阻塞
const data = await fs.promises.readFile('/large-file.json');

// 问题:同步解析大型 JSON
// 不好:大型对象会阻塞
const parsed = JSON.parse(largeJsonString);

// 好:对大数据使用流
import { createReadStream } from 'fs';
import { createInterface } from 'readline';

const rl = createInterface({ input: createReadStream('data.ndjson') });
for await (const line of rl) {
  const item = JSON.parse(line);
  await processItem(item);
}

// 问题:主线程上的 CPU 密集型任务
// 使用 worker_threads 处理 CPU 工作
import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';

if (!isMainThread) {
  const result = heavyComputation(workerData.input);
  parentPort!.postMessage(result);
}

async function runInWorker(input: unknown): Promise<unknown> {
  return new Promise((resolve, reject) => {
    const worker = new Worker(__filename, { workerData: { input } });
    worker.on('message', resolve);
    worker.on('error', reject);
  });
}

使用 autocannon 进行基准测试

# 基本基准测试
npx autocannon http://localhost:3000/api/users -d 10 -c 100

# 选项:
# -d 10      持续时间 10 秒
# -c 100     100 个连接
# -p 10      10 个管道请求

# 比较优化前后
npx autocannon http://localhost:3000/api/users -d 30 -c 50 --json > before.json
# 进行优化
npx autocannon http://localhost:3000/api/users -d 30 -c 50 --json > after.json

在优化之前进行分析——大多数性能问题存在于 10% 的代码中。