Skip to content
On this page

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应用的性能和响应能力,确保应用在高负载下仍能稳定运行。