⚡ Node.js服务器慢得像蜗牛,性能优化实战分享

🎯 学习目标:掌握Node.js性能优化的5个核心技巧,解决服务器响应慢、内存泄漏等问题

📊 难度等级 :中级-高级

🏷️ 技术标签#Node.js #性能优化 #服务器调优 #后端开发

⏱️ 阅读时间:约8分钟


🌟 引言

在Node.js后端开发中,你是否遇到过这样的痛苦:

  • 响应超慢:接口响应时间动辄几秒,用户体验极差,客户投诉不断
  • 内存爆炸:服务器内存使用率飙升,频繁重启,半夜被监控报警吵醒
  • 并发崩溃:用户量稍微增加,服务器就扛不住,502错误满天飞
  • 数据库拖累:查询慢如蜗牛,连接池耗尽,整个系统卡死

今天分享5个Node.js性能优化的核心技巧,让你的服务器从蜗牛变火箭!


💡 核心技巧详解

1. 异步编程优化:让事件循环飞起来

🔍 应用场景

处理大量I/O操作、文件读写、网络请求等场景,避免阻塞主线程。

❌ 常见问题

同步操作阻塞事件循环,导致服务器响应缓慢:

javascript 复制代码
// ❌ 同步文件读取,阻塞事件循环
const fs = require('fs');

const readFileSync = () => {
  try {
    const data = fs.readFileSync('./large-file.txt', 'utf8');
    return data;
  } catch (error) {
    console.error('读取文件失败:', error);
  }
};

// 这会阻塞整个事件循环
app.get('/api/data', (req, res) => {
  const fileData = readFileSync();
  res.json({ data: fileData });
});

✅ 推荐方案

使用异步操作和Promise优化事件循环:

javascript 复制代码
// ✅ 异步文件读取,不阻塞事件循环
const fs = require('fs').promises;

/**
 * 异步读取文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<string>} 文件内容
 */
const readFileAsync = async (filePath) => {
  try {
    const data = await fs.readFile(filePath, 'utf8');
    return data;
  } catch (error) {
    console.error('读取文件失败:', error);
    throw error;
  }
};

/**
 * 批量处理异步任务
 * @param {Array} tasks - 任务数组
 * @returns {Promise<Array>} 处理结果
 */
const processBatchTasks = async (tasks) => {
  const results = await Promise.allSettled(
    tasks.map(task => task())
  );
  return results;
};

// 非阻塞的API接口
app.get('/api/data', async (req, res) => {
  try {
    const fileData = await readFileAsync('./large-file.txt');
    res.json({ data: fileData });
  } catch (error) {
    res.status(500).json({ error: '服务器内部错误' });
  }
});

💡 核心要点

  • 避免同步操作:使用异步版本的API,如fs.promises
  • 合理使用Promise.all:并行处理多个异步任务
  • 错误处理:使用try-catch包装异步操作
  • 事件循环监控:使用process.nextTick()合理调度任务

🎯 实际应用

优化数据库查询和外部API调用:

javascript 复制代码
/**
 * 优化的用户数据获取
 * @param {string} userId - 用户ID
 * @returns {Promise<Object>} 用户完整信息
 */
const getUserData = async (userId) => {
  try {
    // 并行获取用户基础信息和扩展信息
    const [userInfo, userProfile, userStats] = await Promise.all([
      db.users.findById(userId),
      db.profiles.findByUserId(userId),
      db.stats.getUserStats(userId)
    ]);
    
    return {
      ...userInfo,
      profile: userProfile,
      stats: userStats
    };
  } catch (error) {
    console.error('获取用户数据失败:', error);
    throw error;
  }
};

2. 内存管理:告别内存泄漏的噩梦

🔍 应用场景

长时间运行的服务器应用,需要监控和优化内存使用,防止内存泄漏。

❌ 常见问题

内存泄漏导致服务器性能下降甚至崩溃:

javascript 复制代码
// ❌ 内存泄漏的典型案例
const cache = new Map();

// 无限制的缓存增长
const addToCache = (key, value) => {
  cache.set(key, value);
  // 没有清理机制,内存会无限增长
};

// 事件监听器没有正确移除
const setupEventListeners = () => {
  const emitter = new EventEmitter();
  
  setInterval(() => {
    emitter.on('data', (data) => {
      console.log('处理数据:', data);
    });
  }, 1000);
  // 监听器不断累积,造成内存泄漏
};

✅ 推荐方案

实现内存监控和自动清理机制:

javascript 复制代码
// ✅ 内存安全的缓存实现
class MemoryCache {
  constructor(maxSize = 1000, ttl = 300000) { // 5分钟TTL
    this.cache = new Map();
    this.maxSize = maxSize;
    this.ttl = ttl;
    this.timers = new Map();
    
    // 定期清理过期缓存
    this.cleanupInterval = setInterval(() => {
      this.cleanup();
    }, 60000); // 每分钟清理一次
  }

  /**
   * 设置缓存
   * @param {string} key - 缓存键
   * @param {any} value - 缓存值
   */
  set(key, value) {
    // 检查缓存大小限制
    if (this.cache.size >= this.maxSize) {
      const firstKey = this.cache.keys().next().value;
      this.delete(firstKey);
    }

    this.cache.set(key, {
      value,
      timestamp: Date.now()
    });

    // 设置过期定时器
    if (this.timers.has(key)) {
      clearTimeout(this.timers.get(key));
    }
    
    const timer = setTimeout(() => {
      this.delete(key);
    }, this.ttl);
    
    this.timers.set(key, timer);
  }

  /**
   * 获取缓存
   * @param {string} key - 缓存键
   * @returns {any} 缓存值
   */
  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    
    // 检查是否过期
    if (Date.now() - item.timestamp > this.ttl) {
      this.delete(key);
      return null;
    }
    
    return item.value;
  }

  /**
   * 删除缓存
   * @param {string} key - 缓存键
   */
  delete(key) {
    this.cache.delete(key);
    if (this.timers.has(key)) {
      clearTimeout(this.timers.get(key));
      this.timers.delete(key);
    }
  }

  /**
   * 清理过期缓存
   */
  cleanup() {
    const now = Date.now();
    for (const [key, item] of this.cache.entries()) {
      if (now - item.timestamp > this.ttl) {
        this.delete(key);
      }
    }
  }

  /**
   * 销毁缓存实例
   */
  destroy() {
    clearInterval(this.cleanupInterval);
    for (const timer of this.timers.values()) {
      clearTimeout(timer);
    }
    this.cache.clear();
    this.timers.clear();
  }
}

/**
 * 内存使用监控
 */
const monitorMemory = () => {
  const memUsage = process.memoryUsage();
  const formatBytes = (bytes) => (bytes / 1024 / 1024).toFixed(2) + ' MB';
  
  console.log('内存使用情况:');
  console.log(`RSS: ${formatBytes(memUsage.rss)}`);
  console.log(`Heap Used: ${formatBytes(memUsage.heapUsed)}`);
  console.log(`Heap Total: ${formatBytes(memUsage.heapTotal)}`);
  console.log(`External: ${formatBytes(memUsage.external)}`);
  
  // 内存使用率超过阈值时发出警告
  const heapUsedMB = memUsage.heapUsed / 1024 / 1024;
  if (heapUsedMB > 500) { // 500MB阈值
    console.warn('⚠️ 内存使用率过高,建议检查内存泄漏');
  }
};

// 每5分钟监控一次内存使用
setInterval(monitorMemory, 5 * 60 * 1000);

💡 核心要点

  • 缓存大小限制:设置最大缓存条目数,防止无限增长
  • TTL机制:为缓存设置过期时间,自动清理
  • 定时清理:定期清理过期数据和无用对象
  • 内存监控:实时监控内存使用情况,及时发现问题

🎯 实际应用

在Express应用中集成内存管理:

javascript 复制代码
const cache = new MemoryCache(5000, 600000); // 5000条缓存,10分钟TTL

/**
 * 带缓存的数据获取中间件
 */
const cacheMiddleware = (req, res, next) => {
  const cacheKey = `${req.method}:${req.originalUrl}`;
  const cachedData = cache.get(cacheKey);
  
  if (cachedData) {
    return res.json(cachedData);
  }
  
  // 重写res.json方法,自动缓存响应
  const originalJson = res.json;
  res.json = function(data) {
    cache.set(cacheKey, data);
    return originalJson.call(this, data);
  };
  
  next();
};

app.use('/api', cacheMiddleware);

3. 数据库优化:让查询速度飞起来

🔍 应用场景

高并发数据库访问场景,需要优化查询性能和连接管理。

❌ 常见问题

数据库连接管理不当,查询效率低下:

javascript 复制代码
// ❌ 每次查询都创建新连接
const mysql = require('mysql2');

const queryData = async (sql, params) => {
  const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'password',
    database: 'mydb'
  });
  
  // 每次都创建新连接,性能很差
  const [rows] = await connection.execute(sql, params);
  connection.end();
  return rows;
};

// N+1查询问题
const getUsersWithPosts = async () => {
  const users = await queryData('SELECT * FROM users');
  
  for (const user of users) {
    // 每个用户都执行一次查询,性能极差
    user.posts = await queryData('SELECT * FROM posts WHERE user_id = ?', [user.id]);
  }
  
  return users;
};

✅ 推荐方案

使用连接池和查询优化技术:

javascript 复制代码
// ✅ 连接池配置
const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'mydb',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0,
  acquireTimeout: 60000,
  timeout: 60000,
  reconnect: true
});

/**
 * 数据库查询封装
 * @param {string} sql - SQL语句
 * @param {Array} params - 参数数组
 * @returns {Promise<Array>} 查询结果
 */
const query = async (sql, params = []) => {
  try {
    const [rows] = await pool.execute(sql, params);
    return rows;
  } catch (error) {
    console.error('数据库查询失败:', error);
    throw error;
  }
};

/**
 * 批量查询优化
 * @param {Array} userIds - 用户ID数组
 * @returns {Promise<Array>} 用户及其文章数据
 */
const getUsersWithPostsOptimized = async (userIds = []) => {
  try {
    // 一次性获取所有用户
    const usersQuery = userIds.length > 0 
      ? 'SELECT * FROM users WHERE id IN (?)'
      : 'SELECT * FROM users';
    const users = await query(usersQuery, userIds.length > 0 ? [userIds] : []);
    
    if (users.length === 0) return [];
    
    // 一次性获取所有文章
    const userIdList = users.map(user => user.id);
    const posts = await query(
      'SELECT * FROM posts WHERE user_id IN (?)',
      [userIdList]
    );
    
    // 在内存中组装数据
    const postsMap = posts.reduce((map, post) => {
      if (!map[post.user_id]) {
        map[post.user_id] = [];
      }
      map[post.user_id].push(post);
      return map;
    }, {});
    
    return users.map(user => ({
      ...user,
      posts: postsMap[user.id] || []
    }));
  } catch (error) {
    console.error('获取用户文章数据失败:', error);
    throw error;
  }
};

/**
 * 分页查询优化
 * @param {number} page - 页码
 * @param {number} limit - 每页数量
 * @param {Object} filters - 过滤条件
 * @returns {Promise<Object>} 分页结果
 */
const getPaginatedUsers = async (page = 1, limit = 20, filters = {}) => {
  const offset = (page - 1) * limit;
  
  // 构建WHERE条件
  let whereClause = '';
  const params = [];
  
  if (filters.name) {
    whereClause += ' WHERE name LIKE ?';
    params.push(`%${filters.name}%`);
  }
  
  if (filters.status) {
    whereClause += whereClause ? ' AND status = ?' : ' WHERE status = ?';
    params.push(filters.status);
  }
  
  // 并行执行总数查询和数据查询
  const [totalResult, users] = await Promise.all([
    query(`SELECT COUNT(*) as total FROM users${whereClause}`, params),
    query(`SELECT * FROM users${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`, 
          [...params, limit, offset])
  ]);
  
  const total = totalResult[0].total;
  
  return {
    data: users,
    pagination: {
      page,
      limit,
      total,
      totalPages: Math.ceil(total / limit)
    }
  };
};

/**
 * 事务处理封装
 * @param {Function} callback - 事务回调函数
 * @returns {Promise<any>} 事务结果
 */
const transaction = async (callback) => {
  const connection = await 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();
  }
};

// 使用事务的示例
const transferMoney = async (fromUserId, toUserId, amount) => {
  return await transaction(async (conn) => {
    // 检查余额
    const [fromUser] = await conn.execute(
      'SELECT balance FROM users WHERE id = ? FOR UPDATE',
      [fromUserId]
    );
    
    if (fromUser.balance < amount) {
      throw new Error('余额不足');
    }
    
    // 扣款
    await conn.execute(
      'UPDATE users SET balance = balance - ? WHERE id = ?',
      [amount, fromUserId]
    );
    
    // 加款
    await conn.execute(
      'UPDATE users SET balance = balance + ? WHERE id = ?',
      [amount, toUserId]
    );
    
    return { success: true, message: '转账成功' };
  });
};

💡 核心要点

  • 连接池管理:避免频繁创建销毁连接,提高性能
  • 批量查询:解决N+1查询问题,减少数据库往返
  • 索引优化:为常用查询字段添加索引
  • 事务管理:确保数据一致性,正确处理回滚

🎯 实际应用

在API接口中应用数据库优化:

javascript 复制代码
app.get('/api/users', async (req, res) => {
  try {
    const { page = 1, limit = 20, name, status } = req.query;
    const result = await getPaginatedUsers(
      parseInt(page), 
      parseInt(limit), 
      { name, status }
    );
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: '获取用户列表失败' });
  }
});

app.get('/api/users/:id/posts', async (req, res) => {
  try {
    const userId = parseInt(req.params.id);
    const users = await getUsersWithPostsOptimized([userId]);
    res.json(users[0] || null);
  } catch (error) {
    res.status(500).json({ error: '获取用户文章失败' });
  }
});

4. 缓存策略:Redis让你的应用飞起来

🔍 应用场景

频繁访问的数据、计算结果缓存、会话管理、分布式锁等场景。

❌ 常见问题

没有缓存策略,重复计算和查询浪费资源:

javascript 复制代码
// ❌ 每次都重新计算和查询
app.get('/api/dashboard', async (req, res) => {
  // 每次都重新计算统计数据,性能很差
  const userCount = await query('SELECT COUNT(*) as count FROM users');
  const postCount = await query('SELECT COUNT(*) as count FROM posts');
  const todayPosts = await query(
    'SELECT COUNT(*) as count FROM posts WHERE DATE(created_at) = CURDATE()'
  );
  
  // 复杂的数据处理
  const popularPosts = await query(`
    SELECT p.*, COUNT(l.id) as likes 
    FROM posts p 
    LEFT JOIN likes l ON p.id = l.post_id 
    GROUP BY p.id 
    ORDER BY likes DESC 
    LIMIT 10
  `);
  
  res.json({
    userCount: userCount[0].count,
    postCount: postCount[0].count,
    todayPosts: todayPosts[0].count,
    popularPosts
  });
});

✅ 推荐方案

使用Redis实现多层缓存策略:

javascript 复制代码
// ✅ Redis缓存配置
const redis = require('redis');

const redisClient = redis.createClient({
  host: 'localhost',
  port: 6379,
  retry_strategy: (options) => {
    if (options.error && options.error.code === 'ECONNREFUSED') {
      return new Error('Redis服务器拒绝连接');
    }
    if (options.total_retry_time > 1000 * 60 * 60) {
      return new Error('重试时间已用尽');
    }
    if (options.attempt > 10) {
      return undefined;
    }
    return Math.min(options.attempt * 100, 3000);
  }
});

redisClient.on('error', (err) => {
  console.error('Redis连接错误:', err);
});

/**
 * 缓存管理器
 */
class CacheManager {
  constructor(redisClient) {
    this.redis = redisClient;
    this.defaultTTL = 300; // 5分钟默认过期时间
  }

  /**
   * 设置缓存
   * @param {string} key - 缓存键
   * @param {any} value - 缓存值
   * @param {number} ttl - 过期时间(秒)
   */
  async set(key, value, ttl = this.defaultTTL) {
    try {
      const serializedValue = JSON.stringify(value);
      await this.redis.setex(key, ttl, serializedValue);
    } catch (error) {
      console.error('设置缓存失败:', error);
    }
  }

  /**
   * 获取缓存
   * @param {string} key - 缓存键
   * @returns {Promise<any>} 缓存值
   */
  async get(key) {
    try {
      const value = await this.redis.get(key);
      return value ? JSON.parse(value) : null;
    } catch (error) {
      console.error('获取缓存失败:', error);
      return null;
    }
  }

  /**
   * 删除缓存
   * @param {string} key - 缓存键
   */
  async del(key) {
    try {
      await this.redis.del(key);
    } catch (error) {
      console.error('删除缓存失败:', error);
    }
  }

  /**
   * 批量删除缓存(支持通配符)
   * @param {string} pattern - 匹配模式
   */
  async delPattern(pattern) {
    try {
      const keys = await this.redis.keys(pattern);
      if (keys.length > 0) {
        await this.redis.del(...keys);
      }
    } catch (error) {
      console.error('批量删除缓存失败:', error);
    }
  }

  /**
   * 缓存穿透保护
   * @param {string} key - 缓存键
   * @param {Function} fetchFunction - 数据获取函数
   * @param {number} ttl - 过期时间
   * @returns {Promise<any>} 数据
   */
  async getOrSet(key, fetchFunction, ttl = this.defaultTTL) {
    // 先尝试从缓存获取
    let data = await this.get(key);
    
    if (data !== null) {
      return data;
    }
    
    try {
      // 缓存未命中,执行数据获取函数
      data = await fetchFunction();
      
      // 将结果存入缓存
      if (data !== null && data !== undefined) {
        await this.set(key, data, ttl);
      }
      
      return data;
    } catch (error) {
      console.error('数据获取失败:', error);
      throw error;
    }
  }
}

const cacheManager = new CacheManager(redisClient);

/**
 * 仪表板数据获取(带缓存)
 * @returns {Promise<Object>} 仪表板数据
 */
const getDashboardData = async () => {
  const cacheKey = 'dashboard:stats';
  
  return await cacheManager.getOrSet(cacheKey, async () => {
    // 并行执行所有查询
    const [userCount, postCount, todayPosts, popularPosts] = await Promise.all([
      query('SELECT COUNT(*) as count FROM users'),
      query('SELECT COUNT(*) as count FROM posts'),
      query('SELECT COUNT(*) as count FROM posts WHERE DATE(created_at) = CURDATE()'),
      query(`
        SELECT p.*, COUNT(l.id) as likes 
        FROM posts p 
        LEFT JOIN likes l ON p.id = l.post_id 
        GROUP BY p.id 
        ORDER BY likes DESC 
        LIMIT 10
      `)
    ]);
    
    return {
      userCount: userCount[0].count,
      postCount: postCount[0].count,
      todayPosts: todayPosts[0].count,
      popularPosts
    };
  }, 600); // 10分钟缓存
};

/**
 * 用户数据缓存
 * @param {number} userId - 用户ID
 * @returns {Promise<Object>} 用户数据
 */
const getCachedUser = async (userId) => {
  const cacheKey = `user:${userId}`;
  
  return await cacheManager.getOrSet(cacheKey, async () => {
    const [user] = await query('SELECT * FROM users WHERE id = ?', [userId]);
    return user || null;
  }, 1800); // 30分钟缓存
};

/**
 * 缓存失效处理
 */
const invalidateUserCache = async (userId) => {
  await cacheManager.del(`user:${userId}`);
  // 同时清理相关的缓存
  await cacheManager.delPattern(`user:${userId}:*`);
};

/**
 * 分布式锁实现
 * @param {string} lockKey - 锁键
 * @param {number} expireTime - 过期时间(秒)
 * @returns {Promise<boolean>} 是否获取到锁
 */
const acquireLock = async (lockKey, expireTime = 30) => {
  try {
    const result = await redisClient.set(lockKey, '1', 'EX', expireTime, 'NX');
    return result === 'OK';
  } catch (error) {
    console.error('获取锁失败:', error);
    return false;
  }
};

/**
 * 释放分布式锁
 * @param {string} lockKey - 锁键
 */
const releaseLock = async (lockKey) => {
  try {
    await redisClient.del(lockKey);
  } catch (error) {
    console.error('释放锁失败:', error);
  }
};

💡 核心要点

  • 多层缓存:内存缓存 + Redis缓存,提高命中率
  • 缓存穿透保护:避免大量请求直接打到数据库
  • 缓存失效策略:主动失效和被动过期相结合
  • 分布式锁:防止缓存击穿和并发问题

🎯 实际应用

在API中集成缓存策略:

javascript 复制代码
// 带缓存的仪表板接口
app.get('/api/dashboard', async (req, res) => {
  try {
    const data = await getDashboardData();
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: '获取仪表板数据失败' });
  }
});

// 用户更新时清理缓存
app.put('/api/users/:id', async (req, res) => {
  const userId = parseInt(req.params.id);
  
  try {
    await query('UPDATE users SET ? WHERE id = ?', [req.body, userId]);
    
    // 清理相关缓存
    await invalidateUserCache(userId);
    await cacheManager.del('dashboard:stats'); // 清理仪表板缓存
    
    res.json({ success: true });
  } catch (error) {
    res.status(500).json({ error: '更新用户失败' });
  }
});

// 防止重复提交的接口
app.post('/api/orders', async (req, res) => {
  const { userId, productId } = req.body;
  const lockKey = `order:lock:${userId}:${productId}`;
  
  // 获取分布式锁
  const lockAcquired = await acquireLock(lockKey, 10);
  
  if (!lockAcquired) {
    return res.status(429).json({ error: '请勿重复提交订单' });
  }
  
  try {
    // 处理订单逻辑
    const order = await createOrder(userId, productId);
    res.json(order);
  } catch (error) {
    res.status(500).json({ error: '创建订单失败' });
  } finally {
    // 释放锁
    await releaseLock(lockKey);
  }
});

5. 集群部署:PM2让你的应用无懈可击

🔍 应用场景

生产环境部署,需要进程管理、负载均衡、自动重启、零停机更新等功能。

❌ 常见问题

单进程运行,无法充分利用多核CPU,缺乏容错机制:

javascript 复制代码
// ❌ 单进程运行,存在单点故障
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello World');
});

// 单进程运行,无法利用多核CPU
app.listen(3000, () => {
  console.log('服务器运行在端口3000');
});

// 没有错误处理,进程崩溃后无法自动重启
process.on('uncaughtException', (err) => {
  console.error('未捕获的异常:', err);
  process.exit(1); // 进程退出后无法自动重启
});

✅ 推荐方案

使用PM2实现集群部署和进程管理:

javascript 复制代码
// ✅ PM2配置文件 ecosystem.config.js
module.exports = {
  apps: [{
    name: 'my-app',
    script: './app.js',
    instances: 'max', // 根据CPU核心数自动设置进程数
    exec_mode: 'cluster', // 集群模式
    
    // 环境配置
    env: {
      NODE_ENV: 'development',
      PORT: 3000
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    
    // 性能配置
    max_memory_restart: '500M', // 内存超过500M自动重启
    min_uptime: '10s', // 最小运行时间
    max_restarts: 10, // 最大重启次数
    
    // 日志配置
    log_file: './logs/combined.log',
    out_file: './logs/out.log',
    error_file: './logs/error.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    
    // 监控配置
    watch: false, // 生产环境不开启文件监控
    ignore_watch: ['node_modules', 'logs'],
    
    // 其他配置
    autorestart: true, // 自动重启
    merge_logs: true, // 合并日志
    time: true // 日志时间戳
  }]
};

// 优化的应用程序代码 app.js
const express = require('express');
const cluster = require('cluster');
const os = require('os');

const app = express();
const PORT = process.env.PORT || 3000;

// 中间件配置
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

/**
 * 健康检查接口
 */
app.get('/health', (req, res) => {
  const healthCheck = {
    uptime: process.uptime(),
    message: 'OK',
    timestamp: Date.now(),
    pid: process.pid,
    memory: process.memoryUsage()
  };
  
  res.status(200).json(healthCheck);
});

/**
 * 优雅关闭处理
 */
const gracefulShutdown = () => {
  console.log('收到关闭信号,开始优雅关闭...');
  
  server.close(() => {
    console.log('HTTP服务器已关闭');
    
    // 关闭数据库连接
    if (pool) {
      pool.end(() => {
        console.log('数据库连接池已关闭');
        process.exit(0);
      });
    } else {
      process.exit(0);
    }
  });
  
  // 强制关闭超时
  setTimeout(() => {
    console.error('强制关闭进程');
    process.exit(1);
  }, 10000);
};

/**
 * 错误处理
 */
process.on('uncaughtException', (err) => {
  console.error('未捕获的异常:', err);
  // 不立即退出,让PM2处理重启
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的Promise拒绝:', reason);
});

// 优雅关闭信号处理
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);

const server = app.listen(PORT, () => {
  console.log(`进程 ${process.pid} 在端口 ${PORT} 上运行`);
});

/**
 * 性能监控中间件
 */
const performanceMonitor = (req, res, next) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - start;
    
    // 记录慢请求
    if (duration > 1000) {
      console.warn(`慢请求警告: ${req.method} ${req.url} - ${duration}ms`);
    }
    
    // 记录请求日志
    console.log(`${req.method} ${req.url} - ${res.statusCode} - ${duration}ms`);
  });
  
  next();
};

app.use(performanceMonitor);

/**
 * 负载均衡健康检查
 */
app.get('/status', (req, res) => {
  const status = {
    status: 'healthy',
    pid: process.pid,
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    cpu: process.cpuUsage(),
    timestamp: new Date().toISOString()
  };
  
  res.json(status);
});

module.exports = app;

💡 核心要点

  • 集群模式:充分利用多核CPU,提高并发处理能力
  • 自动重启:进程崩溃后自动重启,保证服务可用性
  • 内存监控:内存超限自动重启,防止内存泄漏
  • 优雅关闭:正确处理关闭信号,避免数据丢失

🎯 实际应用

PM2部署和管理命令:

bash 复制代码
# 安装PM2
npm install -g pm2

# 启动应用(开发环境)
pm2 start ecosystem.config.js

# 启动应用(生产环境)
pm2 start ecosystem.config.js --env production

# 查看应用状态
pm2 status

# 查看日志
pm2 logs my-app

# 监控应用
pm2 monit

# 重启应用
pm2 restart my-app

# 零停机重载
pm2 reload my-app

# 停止应用
pm2 stop my-app

# 删除应用
pm2 delete my-app

# 保存PM2配置
pm2 save

# 设置开机自启
pm2 startup

Nginx负载均衡配置:

nginx 复制代码
# nginx.conf
upstream nodejs_backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    server 127.0.0.1:3003;
}

server {
    listen 80;
    server_name your-domain.com;
    
    location / {
        proxy_pass http://nodejs_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
    
    # 健康检查
    location /health {
        proxy_pass http://nodejs_backend/health;
        access_log off;
    }
}

📊 技巧对比总结

技巧 性能提升 实施难度 适用场景
异步编程优化 ⭐⭐⭐⭐⭐ ⭐⭐ 所有I/O密集型应用
内存管理 ⭐⭐⭐⭐ ⭐⭐⭐ 长时间运行的服务
数据库优化 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ 数据库密集型应用
缓存策略 ⭐⭐⭐⭐⭐ ⭐⭐⭐ 高并发读取场景
集群部署 ⭐⭐⭐⭐ ⭐⭐ 生产环境部署

🎯 实战应用建议

最佳实践

  1. 异步编程应用:全面使用async/await,避免同步操作阻塞事件循环
  2. 内存管理应用:实施内存监控和自动清理机制,防止内存泄漏
  3. 数据库优化应用:使用连接池、批量查询、索引优化提升数据库性能
  4. 缓存策略应用:多层缓存架构,合理设置过期时间和失效策略
  5. 集群部署应用:PM2集群模式部署,配合Nginx负载均衡

性能考虑

  • 监控指标:响应时间、内存使用率、CPU使用率、数据库连接数
  • 压力测试:使用工具如Artillery、JMeter进行性能测试
  • 渐进优化:从最影响性能的瓶颈开始优化,逐步改进
  • 生产环境:在生产环境中持续监控和调优

💡 总结

这5个Node.js性能优化技巧能够显著提升服务器性能,让你的应用:

  1. 异步编程优化:通过合理使用异步操作和Promise,让事件循环高效运转,避免阻塞
  2. 内存管理:实施内存监控和自动清理机制,防止内存泄漏导致的性能下降
  3. 数据库优化:使用连接池、批量查询、事务管理等技术,大幅提升数据库操作效率
  4. 缓存策略:多层缓存架构配合Redis,减少数据库压力,提升响应速度
  5. 集群部署:PM2集群模式充分利用多核CPU,提供高可用性和容错能力

掌握这些技巧,你的Node.js应用将从蜗牛变成火箭,用户体验和系统稳定性都会得到质的提升!


🔗 相关资源


💡 今日收获:掌握了5个Node.js性能优化核心技巧,这些知识点能够解决大部分服务器性能问题。

如果这篇文章对你有帮助,欢迎点赞、收藏和分享!有任何问题也欢迎在评论区讨论。 🚀

相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax