正在加载,请稍候…

Node.js 性能优化:性能分析、集群与工作线程

优化 Node.js 应用以实现高吞吐量——涵盖 CPU 性能分析、内存泄漏检测、集群模式、工作线程、libuv 调优及 V8 内部机制。

Node.js 性能优化:性能分析、集群与工作线程

Node.js 性能基础

Node.js 是单线程但高度并发的——理解其事件循环是优化的关键。

Node.js 性能优化:性能分析、集群与工作线程 插图

使用 --prof 进行 CPU 性能分析

# 生成 V8 性能分析文件
node --prof app.js

# 处理性能分析文件
node --prof-process isolate-*.log > profile.txt

# 或使用 clinic.js
npm install -g clinic
clinic doctor -- node app.js
clinic flame -- node app.js

事件循环监控

import { monitorEventLoopDelay } from 'perf_hooks';

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

setInterval(() => {
  console.log({
    min: h.min / 1e6 + 'ms',
    max: h.max / 1e6 + 'ms',
    mean: h.mean / 1e6 + 'ms',
    p99: h.percentile(99) / 1e6 + 'ms',
  });
  h.reset();
}, 5000);

集群模式

// cluster.js
import cluster from 'cluster';
import os from 'os';
import { createServer } from './app.js';

if (cluster.isPrimary) {
  const numCPUs = os.cpus().length;
  console.log(`Primary ${process.pid}: forking ${numCPUs} workers`);
  
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died — restarting`);
    cluster.fork(); // 自动重启
  });
} else {
  const app = createServer();
  app.listen(3000, () => {
    console.log(`Worker ${process.pid}: listening on port 3000`);
  });
}

Node.js 性能优化:性能分析、集群与工作线程 插图

用于 CPU 密集型任务的工作线程

// main.js
import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';
import { cpus } from 'os';

function runWorker(data) {
  return new Promise((resolve, reject) => {
    const worker = new Worker('./worker.js', { workerData: data });
    worker.on('message', resolve);
    worker.on('error', reject);
    worker.on('exit', (code) => {
      if (code !== 0) reject(new Error(`Worker exited with code ${code}`));
    });
  });
}

// 并行处理
const results = await Promise.all(
  chunks.map(chunk => runWorker({ data: chunk }))
);
// worker.js
import { parentPort, workerData } from 'worker_threads';

function heavyComputation(data) {
  // CPU 密集型工作:图像处理、加密、解析
  return data.reduce((acc, n) => acc + n * n, 0);
}

parentPort.postMessage(heavyComputation(workerData.data));

工作线程池

import { Worker } from 'worker_threads';
import { EventEmitter } from 'events';

class WorkerPool extends EventEmitter {
  constructor(workerPath, poolSize = cpus().length) {
    super();
    this.workers = [];
    this.queue = [];
    
    for (let i = 0; i < poolSize; i++) {
      this.addWorker(workerPath);
    }
  }
  
  addWorker(workerPath) {
    const worker = new Worker(workerPath);
    worker.on('message', (result) => {
      worker.busy = false;
      const { resolve } = worker.currentTask;
      resolve(result);
      this.processQueue(worker);
    });
    worker.busy = false;
    this.workers.push(worker);
  }
  
  run(data) {
    return new Promise((resolve, reject) => {
      const freeWorker = this.workers.find(w => !w.busy);
      const task = { data, resolve, reject };
      
      if (freeWorker) {
        this.runTask(freeWorker, task);
      } else {
        this.queue.push(task);
      }
    });
  }
  
  runTask(worker, task) {
    worker.busy = true;
    worker.currentTask = task;
    worker.postMessage(task.data);
  }
  
  processQueue(worker) {
    if (this.queue.length > 0) {
      this.runTask(worker, this.queue.shift());
    }
  }
}

内存泄漏检测

# 使用 node --inspect + Chrome DevTools
node --inspect app.js

# 或使用 heapdump
npm install heapdump

# 按需获取堆快照
process.kill(process.pid, 'SIGUSR2');
// 使用 memwatch-next 检测内存泄漏
import memwatch from '@memwatch/node';

memwatch.on('leak', (info) => {
  console.error('Memory leak detected:', info);
});

memwatch.on('stats', (stats) => {
  console.log('GC stats:', stats);
});

Node.js 性能优化:性能分析、集群与工作线程 插图

大数据流处理

import { Transform, pipeline } from 'stream';
import { promisify } from 'util';

const pipelineAsync = promisify(pipeline);

// 处理大型 CSV 而不加载到内存
await pipelineAsync(
  fs.createReadStream('large-file.csv'),
  csv.parse({ headers: true }),
  new Transform({
    objectMode: true,
    transform(row, encoding, callback) {
      // 处理每一行
      const processed = transformRow(row);
      callback(null, processed);
    }
  }),
  new Transform({
    objectMode: true,
    transform(row, encoding, callback) {
      this.push(JSON.stringify(row) + '\n');
      callback();
    }
  }),
  fs.createWriteStream('output.jsonl')
);

HTTP/2 与 Keep-Alive

import http2 from 'http2';
import fs from 'fs';

const server = http2.createSecureServer({
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem'),
});

// Express 配合 http2
import spdy from 'spdy';
const server = spdy.createServer(
  { key, cert },
  app
);

性能检查清单

  • 在需要时使用 --max-old-space-size 增加堆内存
  • 避免在热路径中使用同步 I/O(如 fs.readFileSync
  • 对性能关键的缓冲区操作使用 Buffer.allocUnsafe()
  • 对于频繁增删操作,优先使用 Map 而非普通对象
  • 使用 Promise.all 进行并行异步操作
  • 在 HTTP 代理中启用 keep-alive
  • 对数据库使用连接池
  • 使用 LRU 缓存缓存昂贵计算的结果