Node.js 性能优化
更新: 8/8/2025 字数: 0 字 时长: 0 分钟
性能优化是构建高质量 Node.js 应用的关键环节。本章将介绍各种性能优化策略和技术。
性能监控和分析
内置性能监控
javascript
// performance/monitor.js
const { performance, PerformanceObserver } = require('perf_hooks');
const process = require('process');
class PerformanceMonitor {
constructor() {
this.metrics = {
requests: 0,
responses: 0,
errors: 0,
avgResponseTime: 0,
memoryUsage: {},
cpuUsage: {}
};
this.startTime = Date.now();
this.setupObservers();
this.startMemoryMonitoring();
}
setupObservers() {
// HTTP 请求性能观察器
const httpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
if (entry.name.startsWith('http-request')) {
this.updateResponseTime(entry.duration);
}
});
});
httpObserver.observe({ entryTypes: ['measure'] });
// GC 性能观察器
const gcObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
console.log(`GC ${entry.kind}: ${entry.duration}ms`);
});
});
gcObserver.observe({ entryTypes: ['gc'] });
}
startMemoryMonitoring() {
setInterval(() => {
this.metrics.memoryUsage = process.memoryUsage();
this.metrics.cpuUsage = process.cpuUsage();
}, 5000);
}
markRequestStart(requestId) {
performance.mark(`request-start-${requestId}`);
this.metrics.requests++;
}
markRequestEnd(requestId) {
performance.mark(`request-end-${requestId}`);
performance.measure(
`http-request-${requestId}`,
`request-start-${requestId}`,
`request-end-${requestId}`
);
this.metrics.responses++;
}
updateResponseTime(duration) {
const currentAvg = this.metrics.avgResponseTime;
const count = this.metrics.responses;
this.metrics.avgResponseTime = (currentAvg * (count - 1) + duration) / count;
}
recordError() {
this.metrics.errors++;
}
getMetrics() {
const uptime = Date.now() - this.startTime;
return {
...this.metrics,
uptime,
requestsPerSecond: this.metrics.requests / (uptime / 1000),
errorRate: this.metrics.errors / this.metrics.requests,
memoryUsageMB: {
rss: Math.round(this.metrics.memoryUsage.rss / 1024 / 1024),
heapTotal: Math.round(this.metrics.memoryUsage.heapTotal / 1024 / 1024),
heapUsed: Math.round(this.metrics.memoryUsage.heapUsed / 1024 / 1024),
external: Math.round(this.metrics.memoryUsage.external / 1024 / 1024)
}
};
}
// 中间件
middleware() {
return (req, res, next) => {
const requestId = `${Date.now()}-${Math.random()}`;
req.performanceId = requestId;
this.markRequestStart(requestId);
// 监听响应结束
res.on('finish', () => {
this.markRequestEnd(requestId);
if (res.statusCode >= 400) {
this.recordError();
}
});
next();
};
}
}
module.exports = new PerformanceMonitor();
使用 Clinic.js 进行性能分析
bash
# 安装 Clinic.js
npm install -g clinic
# 性能分析
clinic doctor -- node app.js
clinic bubbleprof -- node app.js
clinic flame -- node app.js
内存优化
内存泄漏检测和预防
javascript
// utils/memoryManager.js
class MemoryManager {
constructor() {
this.intervals = new Set();
this.timeouts = new Set();
this.eventListeners = new Map();
this.streams = new Set();
}
// 安全的 setInterval
setInterval(callback, delay) {
const id = setInterval(callback, delay);
this.intervals.add(id);
return id;
}
// 安全的 setTimeout
setTimeout(callback, delay) {
const id = setTimeout(() => {
callback();
this.timeouts.delete(id);
}, delay);
this.timeouts.add(id);
return id;
}
// 清理定时器
clearInterval(id) {
clearInterval(id);
this.intervals.delete(id);
}
clearTimeout(id) {
clearTimeout(id);
this.timeouts.delete(id);
}
// 事件监听器管理
addEventListener(emitter, event, listener) {
emitter.on(event, listener);
if (!this.eventListeners.has(emitter)) {
this.eventListeners.set(emitter, new Map());
}
const emitterListeners = this.eventListeners.get(emitter);
if (!emitterListeners.has(event)) {
emitterListeners.set(event, new Set());
}
emitterListeners.get(event).add(listener);
}
removeEventListener(emitter, event, listener) {
emitter.removeListener(event, listener);
const emitterListeners = this.eventListeners.get(emitter);
if (emitterListeners) {
const eventListeners = emitterListeners.get(event);
if (eventListeners) {
eventListeners.delete(listener);
}
}
}
// 流管理
registerStream(stream) {
this.streams.add(stream);
stream.on('close', () => {
this.streams.delete(stream);
});
stream.on('error', () => {
this.streams.delete(stream);
});
}
// 清理所有资源
cleanup() {
// 清理定时器
this.intervals.forEach(id => clearInterval(id));
this.timeouts.forEach(id => clearTimeout(id));
// 清理事件监听器
this.eventListeners.forEach((emitterListeners, emitter) => {
emitterListeners.forEach((listeners, event) => {
listeners.forEach(listener => {
emitter.removeListener(event, listener);
});
});
});
// 关闭流
this.streams.forEach(stream => {
if (!stream.destroyed) {
stream.destroy();
}
});
// 清空集合
this.intervals.clear();
this.timeouts.clear();
this.eventListeners.clear();
this.streams.clear();
}
// 内存使用报告
getMemoryReport() {
const usage = process.memoryUsage();
return {
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`,
activeTimers: this.intervals.size + this.timeouts.size,
activeListeners: Array.from(this.eventListeners.values())
.reduce((total, emitterListeners) => {
return total + Array.from(emitterListeners.values())
.reduce((sum, listeners) => sum + listeners.size, 0);
}, 0),
activeStreams: this.streams.size
};
}
}
module.exports = new MemoryManager();
对象池模式
javascript
// utils/objectPool.js
class ObjectPool {
constructor(createFn, resetFn, maxSize = 100) {
this.createFn = createFn;
this.resetFn = resetFn;
this.maxSize = maxSize;
this.pool = [];
this.created = 0;
this.acquired = 0;
this.released = 0;
}
acquire() {
let obj;
if (this.pool.length > 0) {
obj = this.pool.pop();
} else {
obj = this.createFn();
this.created++;
}
this.acquired++;
return obj;
}
release(obj) {
if (this.pool.length < this.maxSize) {
if (this.resetFn) {
this.resetFn(obj);
}
this.pool.push(obj);
}
this.released++;
}
getStats() {
return {
poolSize: this.pool.length,
created: this.created,
acquired: this.acquired,
released: this.released,
inUse: this.acquired - this.released
};
}
clear() {
this.pool.length = 0;
}
}
// 使用示例:HTTP 请求对象池
class HttpRequestPool {
constructor() {
this.pool = new ObjectPool(
() => ({
url: '',
method: 'GET',
headers: {},
body: null,
timestamp: 0
}),
(obj) => {
obj.url = '';
obj.method = 'GET';
obj.headers = {};
obj.body = null;
obj.timestamp = 0;
},
50
);
}
createRequest(url, method = 'GET', headers = {}, body = null) {
const request = this.pool.acquire();
request.url = url;
request.method = method;
request.headers = { ...headers };
request.body = body;
request.timestamp = Date.now();
return request;
}
releaseRequest(request) {
this.pool.release(request);
}
getStats() {
return this.pool.getStats();
}
}
module.exports = { ObjectPool, HttpRequestPool };
CPU 优化
Worker Threads 使用
javascript
// workers/cpuIntensiveWorker.js
const { parentPort, workerData } = require('worker_threads');
// CPU 密集型任务
function fibonacci(n) {
if (n < 2) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
function primeFactors(n) {
const factors = [];
let divisor = 2;
while (n >= 2) {
if (n % divisor === 0) {
factors.push(divisor);
n = n / divisor;
} else {
divisor++;
}
}
return factors;
}
function processData(data) {
return data.map(item => {
if (item.type === 'fibonacci') {
return {
...item,
result: fibonacci(item.value)
};
} else if (item.type === 'primeFactors') {
return {
...item,
result: primeFactors(item.value)
};
}
return item;
});
}
// 监听主线程消息
parentPort.on('message', (data) => {
try {
const result = processData(data);
parentPort.postMessage({ success: true, result });
} catch (error) {
parentPort.postMessage({ success: false, error: error.message });
}
});
javascript
// services/workerPool.js
const { Worker } = require('worker_threads');
const path = require('path');
class WorkerPool {
constructor(workerScript, poolSize = require('os').cpus().length) {
this.workerScript = workerScript;
this.poolSize = poolSize;
this.workers = [];
this.queue = [];
this.activeJobs = new Map();
this.createWorkers();
}
createWorkers() {
for (let i = 0; i < this.poolSize; i++) {
this.createWorker();
}
}
createWorker() {
const worker = new Worker(this.workerScript);
worker.on('message', (result) => {
const jobId = this.activeJobs.get(worker);
if (jobId) {
const job = this.queue.find(j => j.id === jobId);
if (job) {
if (result.success) {
job.resolve(result.result);
} else {
job.reject(new Error(result.error));
}
// 移除已完成的任务
const index = this.queue.findIndex(j => j.id === jobId);
if (index !== -1) {
this.queue.splice(index, 1);
}
this.activeJobs.delete(worker);
this.processQueue();
}
}
});
worker.on('error', (error) => {
console.error('Worker error:', error);
this.replaceWorker(worker);
});
worker.on('exit', (code) => {
if (code !== 0) {
console.error(`Worker stopped with exit code ${code}`);
this.replaceWorker(worker);
}
});
this.workers.push(worker);
}
replaceWorker(deadWorker) {
const index = this.workers.indexOf(deadWorker);
if (index !== -1) {
this.workers.splice(index, 1);
this.createWorker();
}
// 处理该 worker 的活跃任务
const jobId = this.activeJobs.get(deadWorker);
if (jobId) {
const job = this.queue.find(j => j.id === jobId);
if (job) {
job.reject(new Error('Worker died'));
const index = this.queue.findIndex(j => j.id === jobId);
if (index !== -1) {
this.queue.splice(index, 1);
}
}
this.activeJobs.delete(deadWorker);
}
}
execute(data) {
return new Promise((resolve, reject) => {
const job = {
id: Date.now() + Math.random(),
data,
resolve,
reject,
timestamp: Date.now()
};
this.queue.push(job);
this.processQueue();
});
}
processQueue() {
if (this.queue.length === 0) return;
// 找到空闲的 worker
const availableWorker = this.workers.find(worker => !this.activeJobs.has(worker));
if (availableWorker) {
// 获取队列中最早的任务
const job = this.queue.find(j => !this.activeJobs.has(j));
if (job) {
this.activeJobs.set(availableWorker, job.id);
availableWorker.postMessage(job.data);
}
}
}
getStats() {
return {
poolSize: this.poolSize,
activeWorkers: this.activeJobs.size,
queueLength: this.queue.length,
totalWorkers: this.workers.length
};
}
async terminate() {
await Promise.all(
this.workers.map(worker => worker.terminate())
);
this.workers = [];
this.activeJobs.clear();
this.queue = [];
}
}
module.exports = WorkerPool;
javascript
// services/cpuIntensiveService.js
const WorkerPool = require('./workerPool');
const path = require('path');
class CpuIntensiveService {
constructor() {
this.workerPool = new WorkerPool(
path.join(__dirname, '../workers/cpuIntensiveWorker.js'),
4 // 使用 4 个 worker
);
}
async processLargeDataset(dataset) {
// 将大数据集分块处理
const chunkSize = Math.ceil(dataset.length / 4);
const chunks = [];
for (let i = 0; i < dataset.length; i += chunkSize) {
chunks.push(dataset.slice(i, i + chunkSize));
}
// 并行处理所有块
const results = await Promise.all(
chunks.map(chunk => this.workerPool.execute(chunk))
);
// 合并结果
return results.flat();
}
async calculateFibonacci(numbers) {
const data = numbers.map(n => ({ type: 'fibonacci', value: n }));
return await this.workerPool.execute(data);
}
async findPrimeFactors(numbers) {
const data = numbers.map(n => ({ type: 'primeFactors', value: n }));
return await this.workerPool.execute(data);
}
getStats() {
return this.workerPool.getStats();
}
async shutdown() {
await this.workerPool.terminate();
}
}
module.exports = new CpuIntensiveService();
集群模式
javascript
// cluster.js
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
const app = require('./app');
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 server = app.listen(process.env.PORT || 3000, () => {
console.log(`工作进程 ${process.pid} 启动,端口 ${server.address().port}`);
});
// 优雅关闭工作进程
process.on('SIGTERM', () => {
console.log(`工作进程 ${process.pid} 收到 SIGTERM 信号`);
server.close(() => {
console.log(`工作进程 ${process.pid} 已关闭`);
process.exit(0);
});
});
}
I/O 优化
连接池优化
javascript
// db/connectionPool.js
const mysql = require('mysql2/promise');
class ConnectionPool {
constructor(config) {
this.config = {
host: config.host || 'localhost',
user: config.user || 'root',
password: config.password || '',
database: config.database,
connectionLimit: config.connectionLimit || 10,
queueLimit: config.queueLimit || 0,
acquireTimeout: config.acquireTimeout || 60000,
timeout: config.timeout || 60000,
reconnect: config.reconnect !== false,
reconnectDelay: config.reconnectDelay || 2000
};
this.pool = null;
this.stats = {
created: 0,
acquired: 0,
released: 0,
errors: 0
};
}
async initialize() {
this.pool = mysql.createPool(this.config);
// 监听连接事件
this.pool.on('connection', (connection) => {
this.stats.created++;
console.log(`新连接已建立: ${connection.threadId}`);
});
this.pool.on('acquire', (connection) => {
this.stats.acquired++;
});
this.pool.on('release', (connection) => {
this.stats.released++;
});
this.pool.on('error', (error) => {
this.stats.errors++;
console.error('连接池错误:', error);
});
// 测试连接
try {
const connection = await this.pool.getConnection();
connection.release();
console.log('数据库连接池初始化成功');
} catch (error) {
console.error('数据库连接池初始化失败:', error);
throw error;
}
}
async query(sql, params = []) {
const startTime = Date.now();
try {
const [rows, fields] = await this.pool.execute(sql, params);
const duration = Date.now() - startTime;
if (duration > 1000) {
console.warn(`慢查询检测 (${duration}ms): ${sql}`);
}
return rows;
} catch (error) {
this.stats.errors++;
console.error('查询错误:', error);
throw error;
}
}
async transaction(callback) {
const connection = await this.pool.getConnection();
try {
await connection.beginTransaction();
const result = await callback(connection);
await connection.commit();
return result;
} catch (error) {
await connection.rollback();
throw error;
} finally {
connection.release();
}
}
getStats() {
return {
...this.stats,
poolSize: this.pool ? this.pool.pool.config.connectionLimit : 0,
activeConnections: this.pool ? this.pool.pool._allConnections.length : 0,
idleConnections: this.pool ? this.pool.pool._freeConnections.length : 0
};
}
async close() {
if (this.pool) {
await this.pool.end();
console.log('数据库连接池已关闭');
}
}
}
module.exports = ConnectionPool;
流式处理
javascript
// utils/streamProcessor.js
const { Transform, pipeline } = require('stream');
const { promisify } = require('util');
const pipelineAsync = promisify(pipeline);
class StreamProcessor {
// 批处理转换流
static createBatchTransform(batchSize, processBatch) {
let batch = [];
return new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
batch.push(chunk);
if (batch.length >= batchSize) {
const currentBatch = batch;
batch = [];
processBatch(currentBatch)
.then(results => {
results.forEach(result => this.push(result));
callback();
})
.catch(callback);
} else {
callback();
}
},
flush(callback) {
if (batch.length > 0) {
processBatch(batch)
.then(results => {
results.forEach(result => this.push(result));
callback();
})
.catch(callback);
} else {
callback();
}
}
});
}
// 限流转换流
static createThrottleTransform(maxPerSecond) {
let tokens = maxPerSecond;
let lastRefill = Date.now();
return new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
const now = Date.now();
const timePassed = now - lastRefill;
// 补充令牌
tokens = Math.min(maxPerSecond, tokens + (timePassed / 1000) * maxPerSecond);
lastRefill = now;
if (tokens >= 1) {
tokens -= 1;
this.push(chunk);
callback();
} else {
// 等待直到有令牌可用
const waitTime = (1 - tokens) / maxPerSecond * 1000;
setTimeout(() => {
tokens = 0;
this.push(chunk);
callback();
}, waitTime);
}
}
});
}
// 错误重试转换流
static createRetryTransform(maxRetries, retryDelay, processor) {
return new Transform({
objectMode: true,
async transform(chunk, encoding, callback) {
let attempts = 0;
while (attempts <= maxRetries) {
try {
const result = await processor(chunk);
this.push(result);
callback();
return;
} catch (error) {
attempts++;
if (attempts > maxRetries) {
callback(error);
return;
}
// 等待后重试
await new Promise(resolve => setTimeout(resolve, retryDelay * attempts));
}
}
}
});
}
// 并行处理流
static createParallelTransform(concurrency, processor) {
let activePromises = 0;
const queue = [];
return new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
const processChunk = async () => {
activePromises++;
try {
const result = await processor(chunk);
this.push(result);
} catch (error) {
this.emit('error', error);
} finally {
activePromises--;
// 处理队列中的下一个任务
if (queue.length > 0) {
const nextTask = queue.shift();
nextTask();
}
}
};
if (activePromises < concurrency) {
processChunk();
} else {
queue.push(processChunk);
}
callback();
}
});
}
// 处理大文件
static async processLargeFile(inputPath, outputPath, processor) {
const fs = require('fs');
const readline = require('readline');
const fileStream = fs.createReadStream(inputPath);
const outputStream = fs.createWriteStream(outputPath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
let lineNumber = 0;
const batchSize = 1000;
let batch = [];
for await (const line of rl) {
lineNumber++;
batch.push({ lineNumber, content: line });
if (batch.length >= batchSize) {
const processedBatch = await processor(batch);
for (const item of processedBatch) {
outputStream.write(JSON.stringify(item) + '\n');
}
batch = [];
}
}
// 处理剩余的批次
if (batch.length > 0) {
const processedBatch = await processor(batch);
for (const item of processedBatch) {
outputStream.write(JSON.stringify(item) + '\n');
}
}
outputStream.end();
return new Promise((resolve, reject) => {
outputStream.on('finish', resolve);
outputStream.on('error', reject);
});
}
}
module.exports = StreamProcessor;
缓存优化
多级缓存系统
javascript
// cache/multiLevelCache.js
const NodeCache = require('node-cache');
const redis = require('../db/redis');
class MultiLevelCache {
constructor(options = {}) {
// L1 缓存:内存缓存
this.l1Cache = new NodeCache({
stdTTL: options.l1TTL || 300, // 5分钟
checkperiod: options.l1CheckPeriod || 60, // 1分钟检查一次过期
maxKeys: options.l1MaxKeys || 1000
});
// L2 缓存:Redis
this.l2Cache = redis;
this.stats = {
l1Hits: 0,
l1Misses: 0,
l2Hits: 0,
l2Misses: 0,
sets: 0,
deletes: 0
};
this.l1TTL = options.l1TTL || 300;
this.l2TTL = options.l2TTL || 3600; // 1小时
}
async get(key) {
// 先检查 L1 缓存
const l1Value = this.l1Cache.get(key);
if (l1Value !== undefined) {
this.stats.l1Hits++;
return l1Value;
}
this.stats.l1Misses++;
// 检查 L2 缓存
const l2Value = await this.l2Cache.get(key);
if (l2Value !== null) {
this.stats.l2Hits++;
// 将数据提升到 L1 缓存
this.l1Cache.set(key, l2Value, this.l1TTL);
return l2Value;
}
this.stats.l2Misses++;
return null;
}
async set(key, value, ttl) {
this.stats.sets++;
const l1TTL = ttl || this.l1TTL;
const l2TTL = ttl || this.l2TTL;
// 同时设置 L1 和 L2 缓存
this.l1Cache.set(key, value, l1TTL);
await this.l2Cache.set(key, value, l2TTL);
}
async delete(key) {
this.stats.deletes++;
// 同时删除 L1 和 L2 缓存
this.l1Cache.del(key);
await this.l2Cache.del(key);
}
async clear() {
this.l1Cache.flushAll();
await this.l2Cache.clearAll();
}
// 缓存穿透保护
async getWithFallback(key, fallbackFn, ttl) {
const cached = await this.get(key);
if (cached !== null) {
return cached;
}
// 使用分布式锁防止缓存击穿
const lockKey = `lock:${key}`;
const lockValue = Date.now().toString();
const acquired = await this.l2Cache.set(lockKey, lockValue, 10); // 10秒锁
if (acquired) {
try {
// 再次检查缓存(可能在等待锁的过程中被其他进程设置)
const doubleCheck = await this.get(key);
if (doubleCheck !== null) {
return doubleCheck;
}
// 执行回调获取数据
const value = await fallbackFn();
if (value !== null && value !== undefined) {
await this.set(key, value, ttl);
}
return value;
} finally {
// 释放锁
await this.l2Cache.del(lockKey);
}
} else {
// 等待一段时间后重试
await new Promise(resolve => setTimeout(resolve, 100));
return await this.getWithFallback(key, fallbackFn, ttl);
}
}
// 批量获取
async mget(keys) {
const results = {};
const l2Keys = [];
// 先从 L1 缓存获取
for (const key of keys) {
const l1Value = this.l1Cache.get(key);
if (l1Value !== undefined) {
results[key] = l1Value;
this.stats.l1Hits++;
} else {
l2Keys.push(key);
this.stats.l1Misses++;
}
}
// 从 L2 缓存获取剩余的键
if (l2Keys.length > 0) {
for (const key of l2Keys) {
const l2Value = await this.l2Cache.get(key);
if (l2Value !== null) {
results[key] = l2Value;
this.stats.l2Hits++;
// 提升到 L1 缓存
this.l1Cache.set(key, l2Value, this.l1TTL);
} else {
this.stats.l2Misses++;
}
}
}
return results;
}
// 批量设置
async mset(keyValuePairs, ttl) {
for (const [key, value] of Object.entries(keyValuePairs)) {
await this.set(key, value, ttl);
}
}
getStats() {
const l1Stats = this.l1Cache.getStats();
return {
...this.stats,
l1Size: l1Stats.keys,
l1HitRate: this.stats.l1Hits / (this.stats.l1Hits + this.stats.l1Misses) || 0,
l2HitRate: this.stats.l2Hits / (this.stats.l2Hits + this.stats.l2Misses) || 0,
overallHitRate: (this.stats.l1Hits + this.stats.l2Hits) /
(this.stats.l1Hits + this.stats.l1Misses + this.stats.l2Hits + this.stats.l2Misses) || 0
};
}
}
module.exports = MultiLevelCache;
智能缓存策略
javascript
// cache/smartCache.js
const MultiLevelCache = require('./multiLevelCache');
class SmartCache extends MultiLevelCache {
constructor(options = {}) {
super(options);
this.accessPatterns = new Map(); // 访问模式统计
this.hotKeys = new Set(); // 热点键
this.coldKeys = new Set(); // 冷键
this.hotThreshold = options.hotThreshold || 10; // 热点阈值
this.coldThreshold = options.coldThreshold || 2; // 冷键阈值
this.analysisInterval = options.analysisInterval || 60000; // 分析间隔
this.startAnalysis();
}
async get(key) {
// 记录访问模式
this.recordAccess(key);
return await super.get(key);
}
recordAccess(key) {
const now = Date.now();
const pattern = this.accessPatterns.get(key) || {
count: 0,
lastAccess: now,
frequency: 0
};
pattern.count++;
pattern.lastAccess = now;
pattern.frequency = pattern.count / ((now - (pattern.firstAccess || now)) / 1000 || 1);
if (!pattern.firstAccess) {
pattern.firstAccess = now;
}
this.accessPatterns.set(key, pattern);
}
startAnalysis() {
setInterval(() => {
this.analyzeAccessPatterns();
}, this.analysisInterval);
}
analyzeAccessPatterns() {
const now = Date.now();
const newHotKeys = new Set();
const newColdKeys = new Set();
for (const [key, pattern] of this.accessPatterns.entries()) {
const timeSinceLastAccess = now - pattern.lastAccess;
// 识别热点键
if (pattern.frequency >= this.hotThreshold) {
newHotKeys.add(key);
}
// 识别冷键(长时间未访问)
if (timeSinceLastAccess > 300000 && pattern.count <= this.coldThreshold) { // 5分钟
newColdKeys.add(key);
}
}
this.hotKeys = newHotKeys;
this.coldKeys = newColdKeys;
// 清理冷键
this.cleanupColdKeys();
}
async cleanupColdKeys() {
for (const key of this.coldKeys) {
await this.delete(key);
this.accessPatterns.delete(key);
}
}
// 预热缓存
async warmup(keys, dataLoader) {
const warmupPromises = keys.map(async (key) => {
const exists = await this.get(key);
if (exists === null) {
try {
const data = await dataLoader(key);
if (data !== null && data !== undefined) {
await this.set(key, data);
}
} catch (error) {
console.error(`缓存预热失败 ${key}:`, error);
}
}
});
await Promise.all(warmupPromises);
}
// 智能 TTL
getSmartTTL(key) {
const pattern = this.accessPatterns.get(key);
if (!pattern) {
return this.l1TTL; // 默认 TTL
}
// 热点键使用更长的 TTL
if (this.hotKeys.has(key)) {
return this.l1TTL * 3;
}
// 根据访问频率调整 TTL
const frequencyMultiplier = Math.min(pattern.frequency / this.hotThreshold, 2);
return Math.floor(this.l1TTL * (1 + frequencyMultiplier));
}
async smartSet(key, value) {
const ttl = this.getSmartTTL(key);
await this.set(key, value, ttl);
}
getAnalytics() {
const hotKeysArray = Array.from(this.hotKeys);
const coldKeysArray = Array.from(this.coldKeys);
const topKeys = Array.from(this.accessPatterns.entries())
.sort((a, b) => b[1].frequency - a[1].frequency)
.slice(0, 10)
.map(([key, pattern]) => ({
key,
frequency: pattern.frequency,
count: pattern.count
}));
return {
...this.getStats(),
hotKeysCount: hotKeysArray.length,
coldKeysCount: coldKeysArray.length,
totalTrackedKeys: this.accessPatterns.size,
topKeys
};
}
}
module.exports = SmartCache;
网络优化
HTTP/2 和压缩
javascript
// server/optimizedServer.js
const http2 = require('http2');
const fs = require('fs');
const path = require('path');
const compression = require('compression');
const express = require('express');
class OptimizedServer {
constructor(options = {}) {
this.app = express();
this.options = options;
this.setupMiddleware();
this.setupRoutes();
}
setupMiddleware() {
// 启用压缩
this.app.use(compression({
level: 6, // 压缩级别
threshold: 1024, // 只压缩大于 1KB 的响应
filter: (req, res) => {
// 自定义压缩过滤器
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
}
}));
// 静态文件优化
this.app.use('/static', express.static('public', {
maxAge: '1y', // 缓存一年
etag: true,
lastModified: true,
setHeaders: (res, path) => {
// 根据文件类型设置不同的缓存策略
if (path.endsWith('.html')) {
res.setHeader('Cache-Control', 'public, max-age=300'); // 5分钟
} else if (path.match(/\.(js|css)$/)) {
res.setHeader('Cache-Control', 'public, max-age=31536000'); // 1年
} else if (path.match(/\.(jpg|jpeg|png|gif|ico|svg)$/)) {
res.setHeader('Cache-Control', 'public, max-age=2592000'); // 30天
}
}
}));
// 请求大小限制
this.app.use(express.json({ limit: '10mb' }));
this.app.use(express.urlencoded({ extended: true, limit: '10mb' }));
}
setupRoutes() {
// 健康检查
this.app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: Date.now() });
});
// 性能指标
this.app.get('/metrics', (req, res) => {
const metrics = this.getMetrics();
res.json(metrics);
});
}
// HTTP/2 服务器
createHttp2Server() {
const options = {
key: fs.readFileSync(this.options.keyPath || 'server.key'),
cert: fs.readFileSync(this.options.certPath || 'server.crt'),
allowHTTP1: true // 允许 HTTP/1.1 回退
};
const server = http2.createSecureServer(options, this.app);
// HTTP/2 推送
server.on('stream', (stream, headers) => {
if (headers[':path'] === '/') {
// 推送关键资源
this.pushResources(stream, [
'/static/css/main.css',
'/static/js/main.js'
]);
}
});
return server;
}
pushResources(stream, resources) {
resources.forEach(resource => {
const filePath = path.join(__dirname, '../public', resource);
if (fs.existsSync(filePath)) {
stream.pushStream({ ':path': resource }, (err, pushStream) => {
if (err) {
console.error('推送失败:', err);
return;
}
const fileStream = fs.createReadStream(filePath);
fileStream.pipe(pushStream);
});
}
});
}
// 连接池优化
setupConnectionPool() {
const http = require('http');
const https = require('https');
// HTTP Agent 配置
const httpAgent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
return { httpAgent, httpsAgent };
}
getMetrics() {
const memUsage = process.memoryUsage();
const cpuUsage = process.cpuUsage();
return {
memory: {
rss: Math.round(memUsage.rss / 1024 / 1024),
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024),
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024),
external: Math.round(memUsage.external / 1024 / 1024)
},
cpu: {
user: cpuUsage.user,
system: cpuUsage.system
},
uptime: process.uptime(),
version: process.version
};
}
start(port = 3000) {
if (this.options.http2) {
const server = this.createHttp2Server();
server.listen(port, () => {
console.log(`HTTP/2 服务器运行在端口 ${port}`);
});
return server;
} else {
const server = this.app.listen(port, () => {
console.log(`HTTP/1.1 服务器运行在端口 ${port}`);
});
return server;
}
}
}
module.exports = OptimizedServer;
性能测试和基准测试
基准测试工具
javascript
// benchmark/performanceBenchmark.js
const Benchmark = require('benchmark');
const { performance } = require('perf_hooks');
class PerformanceBenchmark {
constructor() {
this.suites = new Map();
this.results = [];
}
// 创建测试套件
createSuite(name) {
const suite = new Benchmark.Suite(name);
this.suites.set(name, suite);
return suite;
}
// 添加测试用例
addTest(suiteName, testName, testFn, options = {}) {
const suite = this.suites.get(suiteName);
if (!suite) {
throw new Error(`测试套件 ${suiteName} 不存在`);
}
suite.add(testName, testFn, options);
}
// 运行基准测试
async runSuite(suiteName) {
const suite = this.suites.get(suiteName);
if (!suite) {
throw new Error(`测试套件 ${suiteName} 不存在`);
}
return new Promise((resolve) => {
suite
.on('cycle', (event) => {
console.log(String(event.target));
})
.on('complete', function() {
console.log(`最快的是 ${this.filter('fastest').map('name')}`);
resolve(this);
})
.run({ async: true });
});
}
// 内存使用测试
async memoryTest(testFn, iterations = 1000) {
// 强制垃圾回收
if (global.gc) {
global.gc();
}
const initialMemory = process.memoryUsage();
const startTime = performance.now();
for (let i = 0; i < iterations; i++) {
await testFn();
}
const endTime = performance.now();
// 再次强制垃圾回收
if (global.gc) {
global.gc();
}
const finalMemory = process.memoryUsage();
return {
duration: endTime - startTime,
iterations,
avgDuration: (endTime - startTime) / iterations,
memoryDelta: {
rss: finalMemory.rss - initialMemory.rss,
heapTotal: finalMemory.heapTotal - initialMemory.heapTotal,
heapUsed: finalMemory.heapUsed - initialMemory.heapUsed,
external: finalMemory.external - initialMemory.external
}
};
}
// CPU 密集型测试
cpuIntensiveTest(testFn, duration = 5000) {
const startTime = performance.now();
const endTime = startTime + duration;
let iterations = 0;
while (performance.now() < endTime) {
testFn();
iterations++;
}
const actualDuration = performance.now() - startTime;
return {
iterations,
duration: actualDuration,
operationsPerSecond: iterations / (actualDuration / 1000)
};
}
// 并发测试
async concurrencyTest(testFn, concurrency = 10, totalRequests = 1000) {
const startTime = performance.now();
const results = [];
const errors = [];
const executeRequest = async () => {
try {
const requestStart = performance.now();
const result = await testFn();
const requestEnd = performance.now();
results.push({
duration: requestEnd - requestStart,
result
});
} catch (error) {
errors.push(error);
}
};
// 创建并发请求
const batches = [];
for (let i = 0; i < totalRequests; i += concurrency) {
const batchSize = Math.min(concurrency, totalRequests - i);
const batch = Array(batchSize).fill().map(() => executeRequest());
batches.push(Promise.all(batch));
}
await Promise.all(batches);
const endTime = performance.now();
const durations = results.map(r => r.duration);
return {
totalRequests,
successfulRequests: results.length,
failedRequests: errors.length,
totalDuration: endTime - startTime,
avgResponseTime: durations.reduce((a, b) => a + b, 0) / durations.length,
minResponseTime: Math.min(...durations),
maxResponseTime: Math.max(...durations),
requestsPerSecond: results.length / ((endTime - startTime) / 1000),
errors: errors.slice(0, 10) // 只返回前10个错误
};
}
}
module.exports = PerformanceBenchmark;
性能测试示例
javascript
// benchmark/examples.js
const PerformanceBenchmark = require('./performanceBenchmark');
const UserService = require('../services/userService');
const SmartCache = require('../cache/smartCache');
const benchmark = new PerformanceBenchmark();
// 数组操作基准测试
const arraySuite = benchmark.createSuite('Array Operations');
const largeArray = Array.from({ length: 100000 }, (_, i) => i);
benchmark.addTest('Array Operations', 'for loop', () => {
let sum = 0;
for (let i = 0; i < largeArray.length; i++) {
sum += largeArray[i];
}
return sum;
});
benchmark.addTest('Array Operations', 'forEach', () => {
let sum = 0;
largeArray.forEach(num => {
sum += num;
});
return sum;
});
benchmark.addTest('Array Operations', 'reduce', () => {
return largeArray.reduce((sum, num) => sum + num, 0);
});
// 缓存性能测试
async function runCacheTests() {
const cache = new SmartCache();
console.log('\n=== 缓存性能测试 ===');
// 内存测试
const memoryResult = await benchmark.memoryTest(async () => {
const key = `test_${Math.random()}`;
await cache.set(key, { data: 'test data', timestamp: Date.now() });
await cache.get(key);
}, 1000);
console.log('缓存内存测试结果:', memoryResult);
// 并发测试
const concurrencyResult = await benchmark.concurrencyTest(async () => {
// 模拟数据库查询
const users = await UserService.findAll({ limit: 10 });
return users;
}, 20, 500);
console.log('数据库并发测试结果:', concurrencyResult);
}
// 运行所有测试
async function runAllTests() {
console.log('开始性能基准测试...');
// 数组操作测试
await benchmark.runSuite('Array Operations');
// 缓存测试
await runCacheTests();
// 数据库测试
await runDatabaseTests();
console.log('\n所有测试完成!');
}
// 如果直接运行此文件
if (require.main === module) {
runAllTests().catch(console.error);
}
module.exports = {
PerformanceBenchmark,
runAllTests,
runCacheTests,
runDatabaseTests
};
最佳实践
1. 代码优化
- 避免同步操作:使用异步 I/O 操作
- 合理使用缓存:实施多级缓存策略
- 优化数据库查询:使用索引、连接池、查询优化
- 内存管理:及时清理不需要的对象和事件监听器
2. 架构优化
- 微服务架构:将大型应用拆分为小型服务
- 负载均衡:使用集群模式或反向代理
- CDN 使用:静态资源使用 CDN 加速
- 数据库分片:大数据量时考虑分库分表
3. 监控和调试
- 性能监控:使用 APM 工具监控应用性能
- 日志管理:合理的日志级别和日志轮转
- 错误追踪:使用错误追踪服务
- 健康检查:实现应用健康检查端点
4. 部署优化
- 容器化:使用 Docker 容器化部署
- 自动扩缩容:根据负载自动调整实例数量
- 蓝绿部署:零停机时间部署
- 配置管理:环境变量和配置文件管理
性能优化检查清单
开发阶段
测试阶段
部署阶段
常见性能问题和解决方案
1. 内存泄漏
问题:应用内存使用持续增长
解决方案:
- 使用内存分析工具(如 heapdump)
- 及时清理事件监听器
- 避免全局变量积累
- 使用弱引用(WeakMap、WeakSet)
2. CPU 使用率过高
问题:CPU 使用率持续很高
解决方案:
- 使用 Worker Threads 处理 CPU 密集型任务
- 优化算法复杂度
- 使用缓存减少重复计算
- 实现任务队列和限流
3. 数据库连接问题
问题:数据库连接超时或连接池耗尽
解决方案:
- 配置合适的连接池大小
- 实现连接重试机制
- 优化查询性能
- 使用读写分离
4. 响应时间过长
问题:API 响应时间过长
解决方案:
- 实现缓存策略
- 优化数据库查询
- 使用 CDN 加速静态资源
- 实现异步处理
总结
Node.js 性能优化是一个持续的过程,需要从多个维度进行考虑:
- 监控先行:建立完善的性能监控体系
- 分层优化:从代码、架构、部署等多个层面优化
- 测试驱动:通过基准测试和负载测试验证优化效果
- 持续改进:根据监控数据持续优化性能