Node.js 性能优化完全指南:从基础到高级
Node.js
性能优化
内存管理
集群部署
后端开发
JavaScript
Node.js的性能优化是构建高效后端应用的关键。本文将深入探讨内存管理、CPU优化、I/O优化、集群部署等核心话题,提供实用的优化策略和最佳实践,帮助您构建高性能的Node.js应用。
Node.js 性能基础
Node.js基于V8 JavaScript引擎和libuv事件循环,理解这些底层机制对性能优化至关重要:
// 事件循环的基本理解
console.log('同步操作 1');
setImmediate(() => {
console.log('setImmediate');
});
setTimeout(() => {
console.log('setTimeout');
}, 0);
process.nextTick(() => {
console.log('nextTick');
});
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('同步操作 2');
// 输出顺序:
// 同步操作 1
// 同步操作 2
// nextTick
// Promise
// setTimeout
// setImmediate
1. 内存优化
内存泄漏检测与预防
// ❌ 内存泄漏示例
const memoryLeaks = [];
function createLeak() {
const data = new Array(1000000).fill('memory leak');
memoryLeaks.push(data); // 数组持续增长,永不释放
}
// ✅ 正确的内存管理
class DataCache {
constructor(maxSize = 1000) {
this.cache = new Map();
this.maxSize = maxSize;
}
set(key, value) {
// 实现LRU缓存策略
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
get(key) {
const value = this.cache.get(key);
if (value !== undefined) {
// 更新访问顺序
this.cache.delete(key);
this.cache.set(key, value);
}
return value;
}
clear() {
this.cache.clear();
}
}
// 监控内存使用
function monitorMemory() {
const usage = process.memoryUsage();
console.log({
rss: Math.round(usage.rss / 1024 / 1024) + ' MB',
heapTotal: Math.round(usage.heapTotal / 1024 / 1024) + ' MB',
heapUsed: Math.round(usage.heapUsed / 1024 / 1024) + ' MB',
external: Math.round(usage.external / 1024 / 1024) + ' MB'
});
}
setInterval(monitorMemory, 5000);
对象池和缓存优化
// 对象池实现
class ObjectPool {
constructor(createFn, resetFn, initialSize = 10) {
this.createFn = createFn;
this.resetFn = resetFn;
this.pool = [];
// 预创建对象
for (let i = 0; i < initialSize; i++) {
this.pool.push(this.createFn());
}
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : this.createFn();
}
release(obj) {
this.resetFn(obj);
this.pool.push(obj);
}
size() {
return this.pool.length;
}
}
// 使用示例
const bufferPool = new ObjectPool(
() => Buffer.allocUnsafe(1024),
(buffer) => buffer.fill(0),
50
);
function processData(data) {
const buffer = bufferPool.acquire();
try {
// 处理数据
buffer.write(data);
return buffer.toString();
} finally {
bufferPool.release(buffer);
}
}
// WeakMap用于避免内存泄漏
const cache = new WeakMap();
function expensiveOperation(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = performExpensiveCalculation(obj);
cache.set(obj, result);
return result;
}
2. CPU 优化
避免阻塞事件循环
// ❌ 阻塞事件循环
function heavyTask() {
const start = Date.now();
while (Date.now() - start < 5000) {
// 5秒的同步计算
}
return 'Task completed';
}
// ✅ 使用异步分块处理
function heavyTaskAsync(data, callback) {
const chunkSize = 1000;
let index = 0;
function processChunk() {
const endIndex = Math.min(index + chunkSize, data.length);
// 处理当前块
for (let i = index; i < endIndex; i++) {
// 处理 data[i]
}
index = endIndex;
if (index < data.length) {
// 让出控制权给其他任务
setImmediate(processChunk);
} else {
callback('Task completed');
}
}
processChunk();
}
// ✅ 使用Worker Threads处理CPU密集型任务
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
if (isMainThread) {
// 主线程
function createWorker(data) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, {
workerData: data
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
});
}
// 使用Worker
async function processInWorker(heavyData) {
try {
const result = await createWorker(heavyData);
console.log('结果:', result);
} catch (error) {
console.error('Worker错误:', error);
}
}
} else {
// Worker线程
function heavyComputation(data) {
// CPU密集型计算
let result = 0;
for (let i = 0; i < data.length; i++) {
result += Math.sqrt(data[i]);
}
return result;
}
const result = heavyComputation(workerData);
parentPort.postMessage(result);
}
性能监控和分析
// 性能监控中间件
function performanceMiddleware(req, res, next) {
const start = process.hrtime.bigint();
res.on('finish', () => {
const duration = process.hrtime.bigint() - start;
const ms = Number(duration) / 1000000; // 转换为毫秒
console.log(`${req.method} ${req.url} - ${ms.toFixed(2)}ms`);
// 记录慢请求
if (ms > 1000) {
console.warn(`慢请求警告: ${req.url} 耗时 ${ms.toFixed(2)}ms`);
}
});
next();
}
// 使用性能分析
const { performance, PerformanceObserver } = require('perf_hooks');
const obs = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
obs.observe({ entryTypes: ['measure'] });
// 标记性能点
function expensiveFunction() {
performance.mark('expensive-start');
// 一些耗时操作
for (let i = 0; i < 1000000; i++) {
Math.random();
}
performance.mark('expensive-end');
performance.measure('expensive-function', 'expensive-start', 'expensive-end');
}
3. I/O 优化
文件系统优化
const fs = require('fs').promises;
const path = require('path');
// ✅ 使用流处理大文件
const { createReadStream, createWriteStream } = require('fs');
function copyLargeFile(source, destination) {
return new Promise((resolve, reject) => {
const readStream = createReadStream(source);
const writeStream = createWriteStream(destination);
readStream.pipe(writeStream);
writeStream.on('finish', resolve);
writeStream.on('error', reject);
readStream.on('error', reject);
});
}
// ✅ 批量文件操作
async function processFilesInBatches(files, batchSize = 10) {
const results = [];
for (let i = 0; i < files.length; i += batchSize) {
const batch = files.slice(i, i + batchSize);
const batchPromises = batch.map(async (file) => {
try {
const data = await fs.readFile(file, 'utf8');
return { file, success: true, data };
} catch (error) {
return { file, success: false, error: error.message };
}
});
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
}
return results;
}
// ✅ 文件缓存
class FileCache {
constructor(maxAge = 5 * 60 * 1000) { // 5分钟
this.cache = new Map();
this.maxAge = maxAge;
}
async get(filePath) {
const cached = this.cache.get(filePath);
if (cached && Date.now() - cached.timestamp < this.maxAge) {
return cached.data;
}
try {
const stats = await fs.stat(filePath);
const data = await fs.readFile(filePath, 'utf8');
this.cache.set(filePath, {
data,
timestamp: Date.now(),
mtime: stats.mtime
});
return data;
} catch (error) {
this.cache.delete(filePath);
throw error;
}
}
clear() {
this.cache.clear();
}
}
数据库连接优化
// 连接池配置
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'username',
password: 'password',
database: 'database',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
acquireTimeout: 60000,
timeout: 60000,
reconnect: true
});
// ✅ 查询优化
class DatabaseOptimizer {
constructor(pool) {
this.pool = pool;
this.queryCache = new Map();
}
async query(sql, params = []) {
const cacheKey = sql + JSON.stringify(params);
// 简单的查询缓存(适用于只读查询)
if (this.queryCache.has(cacheKey)) {
const cached = this.queryCache.get(cacheKey);
if (Date.now() - cached.timestamp < 30000) { // 30秒缓存
return cached.result;
}
}
try {
const [rows] = await this.pool.execute(sql, params);
// 缓存SELECT查询结果
if (sql.trim().toUpperCase().startsWith('SELECT')) {
this.queryCache.set(cacheKey, {
result: rows,
timestamp: Date.now()
});
}
return rows;
} catch (error) {
console.error('数据库查询错误:', error);
throw error;
}
}
// 批量插入优化
async batchInsert(table, data, batchSize = 1000) {
if (!data.length) return;
const columns = Object.keys(data[0]);
const placeholders = columns.map(() => '?').join(',');
const sql = `INSERT INTO ${table} (${columns.join(',')}) VALUES (${placeholders})`;
const results = [];
for (let i = 0; i < data.length; i += batchSize) {
const batch = data.slice(i, i + batchSize);
const values = batch.map(row => columns.map(col => row[col]));
try {
const batchResults = await Promise.all(
values.map(row => this.pool.execute(sql, row))
);
results.push(...batchResults);
} catch (error) {
console.error(`批量插入失败 (批次 ${i}-${i + batch.length}):`, error);
throw error;
}
}
return results;
}
}
4. 网络和HTTP优化
const express = require('express');
const compression = require('compression');
const helmet = require('helmet');
const app = express();
// ✅ 启用压缩
app.use(compression({
level: 6,
threshold: 1024,
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
}
}));
// ✅ 安全头
app.use(helmet());
// ✅ 请求限流
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 100个请求
message: '请求过于频繁,请稍后再试',
standardHeaders: true,
legacyHeaders: false
});
app.use('/api/', limiter);
// ✅ 缓存控制
function setCacheHeaders(req, res, next) {
if (req.url.match(/\.(css|js|png|jpg|jpeg|gif|ico|svg)$/)) {
res.setHeader('Cache-Control', 'public, max-age=31536000'); // 1年
} else if (req.url.startsWith('/api/')) {
res.setHeader('Cache-Control', 'no-cache');
}
next();
}
app.use(setCacheHeaders);
// ✅ HTTP/2 和 Keep-Alive
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem')
});
server.on('stream', (stream, headers) => {
if (headers[':method'] === 'GET') {
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('<h1>Hello HTTP/2!</h1>');
}
});
// ✅ 连接池优化
const http = require('http');
const https = require('https');
const httpAgent = new http.Agent({
keepAlive: true,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
const httpsAgent = new https.Agent({
keepAlive: true,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
// 在请求中使用代理
const axios = require('axios');
const client = axios.create({
httpAgent,
httpsAgent,
timeout: 30000
});
5. 集群和部署优化
// ✅ 集群模式
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
// 创建工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
console.log('重新启动工作进程...');
cluster.fork();
});
// 优雅关闭
process.on('SIGTERM', () => {
console.log('收到SIGTERM信号,正在关闭...');
for (const id in cluster.workers) {
cluster.workers[id].kill();
}
});
} else {
// 工作进程
const app = require('./app');
const server = app.listen(3000, () => {
console.log(`工作进程 ${process.pid} 在端口 3000 上启动`);
});
// 优雅关闭
process.on('SIGTERM', () => {
console.log('工作进程收到SIGTERM信号');
server.close(() => {
console.log('HTTP服务器已关闭');
process.exit(0);
});
});
}
// ✅ PM2 配置示例 (ecosystem.config.js)
module.exports = {
apps: [{
name: 'my-app',
script: 'app.js',
instances: 'max', // 或者指定数字
exec_mode: 'cluster',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
},
max_memory_restart: '1G',
error_file: './logs/err.log',
out_file: './logs/out.log',
log_file: './logs/combined.log',
time: true
}]
};
// ✅ 健康检查
function createHealthCheck() {
return (req, res) => {
const healthcheck = {
uptime: process.uptime(),
message: 'OK',
timestamp: Date.now(),
memory: process.memoryUsage(),
pid: process.pid
};
try {
res.status(200).send(healthcheck);
} catch (error) {
healthcheck.message = error;
res.status(503).send();
}
};
}
app.get('/health', createHealthCheck());
性能监控和工具
// ✅ 自定义性能监控
class PerformanceMonitor {
constructor() {
this.metrics = {
requests: 0,
errors: 0,
responseTime: [],
memoryUsage: [],
cpuUsage: []
};
this.startMonitoring();
}
recordRequest(duration, isError = false) {
this.metrics.requests++;
this.metrics.responseTime.push(duration);
if (isError) {
this.metrics.errors++;
}
// 保持最近1000个请求的数据
if (this.metrics.responseTime.length > 1000) {
this.metrics.responseTime.shift();
}
}
startMonitoring() {
setInterval(() => {
// 记录内存使用
const memory = process.memoryUsage();
this.metrics.memoryUsage.push({
timestamp: Date.now(),
rss: memory.rss,
heapUsed: memory.heapUsed
});
// 保持最近100个记录
if (this.metrics.memoryUsage.length > 100) {
this.metrics.memoryUsage.shift();
}
}, 5000);
}
getStats() {
const responseTime = this.metrics.responseTime;
const avgResponseTime = responseTime.length > 0
? responseTime.reduce((a, b) => a + b) / responseTime.length
: 0;
return {
totalRequests: this.metrics.requests,
totalErrors: this.metrics.errors,
errorRate: this.metrics.requests > 0
? (this.metrics.errors / this.metrics.requests * 100).toFixed(2) + '%'
: '0%',
avgResponseTime: avgResponseTime.toFixed(2) + 'ms',
currentMemory: process.memoryUsage(),
uptime: process.uptime()
};
}
}
const monitor = new PerformanceMonitor();
// 在中间件中使用
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
const isError = res.statusCode >= 400;
monitor.recordRequest(duration, isError);
});
next();
});
// 性能报告接口
app.get('/metrics', (req, res) => {
res.json(monitor.getStats());
});
最佳实践总结
✅ 性能优化检查清单:
- 使用最新版本的Node.js和依赖包
- 启用HTTP压缩和缓存
- 实现适当的错误处理和日志记录
- 使用连接池管理数据库连接
- 监控内存使用和垃圾回收
- 避免阻塞事件循环的同步操作
- 实现健康检查和性能监控
- 使用集群模式充分利用多核CPU
⚠️ 常见性能陷阱:
- 同步I/O操作阻塞事件循环
- 内存泄漏导致应用崩溃
- 未正确配置数据库连接池
- 过度使用递归导致栈溢出
- 未实现适当的缓存策略
- 忽略错误处理和监控
推荐工具和资源
🛠️ 性能分析工具:
- Clinic.js - 综合性能诊断工具
- 0x - 火焰图生成器
- autocannon - HTTP基准测试工具
- PM2 - 生产环境进程管理器
- New Relic / AppDynamics - 应用性能监控
- Chrome DevTools - Node.js调试和分析
总结
Node.js性能优化是一个系统性工程,需要从内存管理、CPU使用、I/O优化、网络配置等多个维度进行考虑。通过合理的架构设计、代码优化、监控机制和部署策略,可以显著提升应用性能。记住,性能优化应该基于实际的性能分析数据,而不是猜测。始终先测量,再优化,然后验证优化效果。