
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`);
});
}
用于 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);
});
大数据流处理
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 缓存缓存昂贵计算的结果