⚡ 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性能优化核心技巧,这些知识点能够解决大部分服务器性能问题。

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

相关推荐
曲意已决6 分钟前
《深入源码理解webpac构建流程》
前端·javascript
去伪存真16 分钟前
前端如何让一套构建产物,可以部署多个环境?
前端
KubeSphere22 分钟前
EdgeWize v3.1.1 边缘 AI 网关功能深度解析:打造企业级边缘智能新体验
前端
掘金安东尼34 分钟前
解读 hidden=until-found 属性
前端·javascript·面试
1024小神42 分钟前
jsPDF 不同屏幕尺寸 生成的pdf不一致,怎么解决
前端·javascript
滕本尊42 分钟前
构建可扩展的 DSL 驱动前端框架:从 CRUD 到领域模型的跃迁
前端·全栈
借月43 分钟前
高德地图绘制工具全解析:线路、矩形、圆形、多边形绘制与编辑指南 🗺️✏️
前端·vue.js
li理43 分钟前
NavPathStack 是鸿蒙 Navigation 路由的核心控制器
前端
二闹1 小时前
一招帮你记住上次读到哪儿了?
前端
li理1 小时前
核心概念:Navigation路由生命周期是什么
前端