Appearance
Node.js 性能优化
Node.js应用的性能优化是确保应用高效运行的关键。本章详细介绍各种性能优化策略和最佳实践。
性能分析工具
内置性能钩子
javascript
// 使用Node.js内置性能钩子
const { PerformanceObserver, performance } = require('perf_hooks');
// 监听性能指标
const obs = new PerformanceObserver((items) => {
items.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
obs.observe({ entryTypes: ['measure', 'navigation', 'mark'] });
// 性能标记和测量
performance.mark('start');
// 执行一些操作
for (let i = 0; i < 1000000; i++) {
// 模拟工作
}
performance.mark('end');
performance.measure('operation', 'start', 'end');
使用clinic.js进行性能分析
bash
# 安装clinic.js
npm install -g clinic
# 运行性能分析
clinic doctor -- node app.js
# 运行bubleprof进行CPU分析
clinic bubbleprof -- node app.js
# 运行flame对于火焰图分析
clinic flame -- node app.js
使用clinic.js的示例代码
javascript
// app.js - 需要分析的应用
const express = require('express');
const app = express();
app.get('/', (req, res) => {
// 模拟一些计算
let result = 0;
for (let i = 0; i < 1000000; i++) {
result += i * 0.001;
}
res.json({ result, timestamp: Date.now() });
});
app.listen(3000, () => {
console.log('服务器运行在端口3000');
});
代码优化
避免阻塞事件循环
javascript
// 阻塞事件循环的错误示例
function badExample() {
const largeArray = new Array(10000000).fill(0);
// 这会阻塞事件循环
for (let i = 0; i < largeArray.length; i++) {
largeArray[i] = i * 2;
}
return largeArray;
}
// 非阻塞的正确示例
function goodExample() {
return new Promise((resolve) => {
const largeArray = new Array(10000000).fill(0);
let i = 0;
const batchSize = 10000;
function processBatch() {
const end = Math.min(i + batchSize, largeArray.length);
for (; i < end; i++) {
largeArray[i] = i * 2;
}
if (i < largeArray.length) {
setImmediate(processBatch); // 让出控制权给其他任务
} else {
resolve(largeArray);
}
}
processBatch();
});
}
// 使用示例
goodExample().then(result => {
console.log('处理完成,数组长度:', result.length);
});
优化循环和算法
javascript
// 低效的数组操作
function inefficientArrayOperation(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 2 === 0) {
result.push(arr[i] * 2); // 频繁的数组扩容
}
}
return result;
}
// 高效的数组操作
function efficientArrayOperation(arr) {
// 预估结果数组大小
const result = new Array(arr.length); // 或使用更精确的估算
let resultIndex = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 2 === 0) {
result[resultIndex++] = arr[i] * 2;
}
}
result.length = resultIndex; // 调整数组长度
return result;
}
// 或者使用filter和map的组合(在某些情况下)
function functionalApproach(arr) {
return arr
.filter(x => x % 2 === 0)
.map(x => x * 2);
}
内存优化
javascript
// 内存泄漏示例
class MemoryLeakExample {
constructor() {
this.cache = new Map();
this.setupInterval();
}
setupInterval() {
// 这个定时器会持续运行并保持对实例的引用
this.interval = setInterval(() => {
const data = this.generateData();
this.cache.set(Date.now(), data);
// 缓存不断增长,没有清理机制
}, 1000);
}
generateData() {
return new Array(10000).fill(Math.random());
}
cleanup() {
clearInterval(this.interval);
this.cache.clear();
}
}
// 内存优化示例
class OptimizedExample {
constructor() {
this.cache = new Map();
this.maxCacheSize = 1000;
this.setupInterval();
}
setupInterval() {
this.interval = setInterval(() => {
const data = this.generateData();
this.cache.set(Date.now(), data);
// 限制缓存大小
if (this.cache.size > this.maxCacheSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
}, 1000);
}
generateData() {
return new Array(1000).fill(Math.random());
}
cleanup() {
clearInterval(this.interval);
this.cache.clear();
}
}
异步操作优化
批量操作
javascript
// 低效的逐个操作
async function inefficientSequentialOperations(ids) {
const results = [];
for (const id of ids) {
const result = await fetchUserData(id); // 串行执行
results.push(result);
}
return results;
}
// 高效的批量操作
async function efficientParallelOperations(ids) {
const promises = ids.map(id => fetchUserData(id));
const results = await Promise.all(promises);
return results;
}
// 控制并发数量的批量操作
async function controlledConcurrencyOperations(ids, concurrency = 5) {
const results = [];
const executing = [];
for (const [index, id] of ids.entries()) {
const promise = fetchUserData(id).then(result => {
results[index] = result;
});
executing.push(promise);
if (executing.length >= concurrency) {
await Promise.race(executing); // 等待第一个完成
executing.splice(executing.findIndex(p => p === promise), 1);
}
}
await Promise.all(executing);
return results;
}
// 模拟异步操作
function fetchUserData(id) {
return new Promise(resolve => {
setTimeout(() => {
resolve({ id, name: `User${id}`, email: `user${id}@example.com` });
}, Math.random() * 100);
});
}
流式处理大数据
javascript
const fs = require('fs');
const readline = require('readline');
// 流式处理大文件
async function processLargeFile(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
let lineCount = 0;
let processedCount = 0;
for await (const line of rl) {
lineCount++;
// 处理每一行
if (line.includes('important')) {
processedCount++;
// 执行重要行的处理逻辑
}
// 定期报告进度
if (lineCount % 10000 === 0) {
console.log(`处理了 ${lineCount} 行`);
}
}
return { totalLines: lineCount, processedLines: processedCount };
}
// 使用Transform流进行数据转换
const { Transform } = require('stream');
class DataProcessor extends Transform {
constructor(options) {
super(options);
this.processedCount = 0;
}
_transform(chunk, encoding, callback) {
// 异步处理数据块
setImmediate(() => {
const processedChunk = this.processChunk(chunk);
this.processedCount++;
callback(null, processedChunk);
});
}
processChunk(chunk) {
// 实际的数据处理逻辑
return chunk.toString().toUpperCase();
}
}
// 使用流处理器
function processStream(inputStream, outputStream) {
const processor = new DataProcessor();
inputStream
.pipe(processor)
.pipe(outputStream);
processor.on('finish', () => {
console.log(`处理完成,共处理 ${processor.processedCount} 个数据块`);
});
}
缓存策略
应用级缓存
javascript
// 简单的内存缓存
class SimpleCache {
constructor(options = {}) {
this.cache = new Map();
this.maxSize = options.maxSize || 1000;
this.defaultTTL = options.defaultTTL || 300000; // 5分钟
this.cleanupInterval = options.cleanupInterval || 60000; // 1分钟
// 启动定期清理
this.startCleanup();
}
set(key, value, ttl = this.defaultTTL) {
const expiration = Date.now() + ttl;
this.cache.set(key, { value, expiration });
// 如果缓存大小超过限制,删除最旧的条目
if (this.cache.size > this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
}
get(key) {
const item = this.cache.get(key);
if (!item) {
return undefined;
}
if (Date.now() > item.expiration) {
this.cache.delete(key);
return undefined;
}
return item.value;
}
has(key) {
const item = this.cache.get(key);
if (!item) {
return false;
}
if (Date.now() > item.expiration) {
this.cache.delete(key);
return false;
}
return true;
}
delete(key) {
return this.cache.delete(key);
}
clear() {
this.cache.clear();
}
startCleanup() {
setInterval(() => {
const now = Date.now();
for (const [key, item] of this.cache) {
if (now > item.expiration) {
this.cache.delete(key);
}
}
}, this.cleanupInterval);
}
}
// 使用缓存优化数据库查询
class CachedUserService {
constructor(db) {
this.db = db;
this.cache = new SimpleCache({ maxSize: 1000, defaultTTL: 300000 }); // 5分钟TTL
}
async getUser(id) {
// 首先尝试从缓存获取
const cachedUser = this.cache.get(`user:${id}`);
if (cachedUser) {
console.log('从缓存获取用户');
return cachedUser;
}
// 从数据库获取
const user = await this.db.getUserById(id);
if (user) {
// 存入缓存
this.cache.set(`user:${id}`, user);
console.log('从数据库获取用户并缓存');
}
return user;
}
async updateUser(id, updateData) {
// 更新数据库
const updatedUser = await this.db.updateUser(id, updateData);
// 更新缓存
if (updatedUser) {
this.cache.set(`user:${id}`, updatedUser);
}
return updatedUser;
}
async deleteUser(id) {
// 从数据库删除
await this.db.deleteUser(id);
// 从缓存删除
this.cache.delete(`user:${id}`);
}
}
Redis缓存
javascript
// Redis缓存实现
const redis = require('redis');
class RedisCache {
constructor(options = {}) {
this.client = redis.createClient({
host: options.host || 'localhost',
port: options.port || 6379,
retry_strategy: (options) => {
if (options.error && options.error.code === 'ECONNREFUSED') {
console.error('Redis服务器拒绝连接');
return new Error('Redis连接失败');
}
if (options.total_retry_time > 1000 * 60 * 60) {
return new Error('Redis重试时间过长');
}
if (options.attempt > 10) {
return undefined;
}
return Math.min(options.attempt * 100, 3000);
}
});
this.client.on('error', (err) => {
console.error('Redis错误:', err);
});
}
async connect() {
await this.client.connect();
}
async set(key, value, ttl = 300) { // 默认5分钟TTL
await this.client.setEx(key, ttl, JSON.stringify(value));
}
async get(key) {
const value = await this.client.get(key);
return value ? JSON.parse(value) : null;
}
async del(key) {
await this.client.del(key);
}
async exists(key) {
const result = await this.client.exists(key);
return result === 1;
}
async close() {
await this.client.quit();
}
}
// 使用Redis缓存的用户服务
class RedisCachedUserService {
constructor(db, redisCache) {
this.db = db;
this.cache = redisCache;
}
async getUser(id) {
// 尝试从Redis获取
let user = await this.cache.get(`user:${id}`);
if (!user) {
// 从数据库获取
user = await this.db.getUserById(id);
if (user) {
// 存入Redis缓存,设置较短的TTL
await this.cache.set(`user:${id}`, user, 300); // 5分钟
}
}
return user;
}
}
集群和多进程
集群模式
javascript
// cluster.js
const cluster = require('cluster');
const http = require('http');
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} 已退出`);
// 重启工作进程
cluster.fork();
});
} else {
// 工作进程可以共享任何TCP连接
// 在这个例子中,共享的是HTTP服务器
http.createServer((req, res) => {
res.writeHead(200);
res.end(`Hello World from worker ${process.pid}`);
}).listen(8000);
console.log(`工作进程 ${process.pid} 已启动`);
}
Worker Threads
javascript
// worker_threads.js
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
if (isMainThread) {
// 主线程
module.exports = function parseJSAsync(script) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, {
workerData: { script }
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
});
};
} else {
// 工作线程
const { parse } = require('some-js-parsing-library');
const script = workerData.script;
parentPort.postMessage(parse(script));
}
数据库优化
查询优化
javascript
// 数据库查询优化示例
class OptimizedUserService {
constructor(db) {
this.db = db;
}
// 使用索引的查询
async findActiveUsersByAge(minAge, maxAge) {
// 确保age和isActive字段有索引
const query = `
SELECT * FROM users
WHERE is_active = 1
AND age >= ?
AND age <= ?
ORDER BY created_at DESC
LIMIT 100
`;
return await this.db.query(query, [minAge, maxAge]);
}
// 批量更新
async batchUpdateUserStatus(userIds, status) {
if (!userIds.length) return 0;
const placeholders = userIds.map(() => '?').join(',');
const query = `
UPDATE users
SET status = ?
WHERE id IN (${placeholders})
`;
const params = [status, ...userIds];
const result = await this.db.query(query, params);
return result.affectedRows;
}
// 分页查询优化
async getUsersWithPagination(page = 1, limit = 10) {
const offset = (page - 1) * limit;
// 获取总数(可以考虑缓存)
const countQuery = 'SELECT COUNT(*) as count FROM users';
const [countResult] = await this.db.query(countQuery);
const total = countResult[0].count;
// 获取分页数据
const dataQuery = `
SELECT id, name, email, created_at
FROM users
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`;
const data = await this.db.query(dataQuery, [limit, offset]);
return {
data,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
}
};
}
}
应用级优化
Express应用优化
javascript
const express = require('express');
const compression = require('compression');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const app = express();
// 启用压缩
app.use(compression());
// 安全头
app.use(helmet());
// 速率限制
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 限制每个IP 15分钟内最多100个请求
});
app.use(limiter);
// 静态文件服务优化
app.use(express.static('public', {
maxAge: '1d', // 设置缓存
etag: true, // 启用ETag
lastModified: true
}));
// 解析JSON的优化
app.use(express.json({
limit: '10mb', // 限制请求大小
type: 'application/json'
}));
// 使用连接池
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb',
connectionLimit: 10,
queueLimit: 0,
acquireTimeout: 60000,
timeout: 60000
});
app.get('/api/users', async (req, res) => {
try {
const [rows] = await pool.execute('SELECT * FROM users LIMIT 100');
res.json(rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: '服务器错误' });
}
});
监控和度量
性能监控
javascript
const os = require('os');
class PerformanceMonitor {
constructor() {
this.metrics = {
memory: [],
cpu: [],
eventLoop: []
};
this.startMonitoring();
}
startMonitoring() {
// 内存监控
setInterval(() => {
const memoryUsage = process.memoryUsage();
this.metrics.memory.push({
timestamp: Date.now(),
usage: memoryUsage,
heapUsedPercent: (memoryUsage.heapUsed / memoryUsage.heapTotal) * 100
});
// 限制历史数据大小
if (this.metrics.memory.length > 100) {
this.metrics.memory.shift();
}
}, 5000); // 每5秒监控一次
// CPU监控
let lastCpuUsage = process.cpuUsage();
setInterval(() => {
const currentCpuUsage = process.cpuUsage();
const elapTime = process.hrtime();
const cpuPercent =
(currentCpuUsage.user - lastCpuUsage.user) /
(elapTime[0] * 1e6 + elapTime[1] / 1e3);
this.metrics.cpu.push({
timestamp: Date.now(),
usage: cpuPercent,
load: os.loadavg()
});
if (this.metrics.cpu.length > 100) {
this.metrics.cpu.shift();
}
lastCpuUsage = currentCpuUsage;
}, 5000);
}
getMetrics() {
return {
memory: this.metrics.memory[this.metrics.memory.length - 1],
cpu: this.metrics.cpu[this.metrics.cpu.length - 1],
eventLoop: this.metrics.eventLoop[this.metrics.eventLoop.length - 1]
};
}
getHistoricalMetrics() {
return this.metrics;
}
}
// 使用性能监控
const monitor = new PerformanceMonitor();
// API端点来获取性能指标
app.get('/api/metrics', (req, res) => {
res.json(monitor.getMetrics());
});
生产环境优化
环境配置优化
javascript
// 根据环境优化配置
const isProduction = process.env.NODE_ENV === 'production';
// V8引擎优化标志
if (isProduction) {
// 设置堆内存限制
process.env.NODE_OPTIONS = '--max-old-space-size=4096'; // 4GB
}
// 连接池配置
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: isProduction ? 20 : 5,
queueLimit: 0,
acquireTimeout: 60000,
timeout: 60000
};
// 缓存配置
const cacheConfig = {
max: isProduction ? 10000 : 1000,
ttl: isProduction ? 300000 : 60000 // 生产环境5分钟,开发环境1分钟
};
通过这些性能优化策略,可以显著提升Node.js应用的性能和响应能力,确保应用在高负载下仍能稳定运行。