Skip to content

Node.js 性能优化指南 ​

🎯 概述 ​

Node.js 是一个基于Chrome V8引擎的JavaScript运行时,广泛用于构建高性能的网络应用。本文将分享Node.js性能优化的实用技巧。

📚 核心优化策略 ​

1. 异步编程最佳实践 ​

javascript
// ❌ 错误:阻塞式操作
function processData() {
  const data = fs.readFileSync('large-file.txt', 'utf8')
  const processed = data.split('\n').map(line => line.toUpperCase())
  return processed
}

// ✅ 正确:异步操作
async function processData() {
  try {
    const data = await fs.promises.readFile('large-file.txt', 'utf8')
    const processed = data.split('\n').map(line => line.toUpperCase())
    return processed
  } catch (error) {
    console.error('Error processing file:', error)
    throw error
  }
}

2. 内存管理 ​

javascript
// 使用流处理大文件
const fs = require('fs')
const { Transform } = require('stream')

function processLargeFile(inputPath, outputPath) {
  const readStream = fs.createReadStream(inputPath)
  const writeStream = fs.createWriteStream(outputPath)
  
  const transformStream = new Transform({
    transform(chunk, encoding, callback) {
      const processed = chunk.toString().toUpperCase()
      callback(null, processed)
    }
  })
  
  readStream
    .pipe(transformStream)
    .pipe(writeStream)
    .on('error', (error) => {
      console.error('Stream error:', error)
    })
    .on('finish', () => {
      console.log('File processing completed')
    })
}

🚀 性能优化技巧 ​

1. 缓存策略 ​

javascript
const NodeCache = require('node-cache')
const cache = new NodeCache({ stdTTL: 600 }) // 10分钟缓存

async function getExpensiveData(key) {
  // 先检查缓存
  const cached = cache.get(key)
  if (cached) {
    return cached
  }
  
  // 缓存未命中,从数据库获取
  const data = await database.query('SELECT * FROM expensive_table WHERE key = ?', [key])
  
  // 存入缓存
  cache.set(key, data)
  return data
}

2. 连接池管理 ​

javascript
const mysql = require('mysql2/promise')

// 创建连接池
const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'mydb',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
})

async function queryDatabase(sql, params) {
  const connection = await pool.getConnection()
  try {
    const [rows] = await connection.execute(sql, params)
    return rows
  } finally {
    connection.release()
  }
}

3. 集群模式 ​

javascript
const cluster = require('cluster')
const numCPUs = require('os').cpus().length

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`)
  
  // 创建工作进程
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork()
  }
  
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`)
    cluster.fork() // 重启工作进程
  })
} else {
  // 工作进程
  const express = require('express')
  const app = express()
  
  app.get('/', (req, res) => {
    res.json({ message: 'Hello from worker ' + process.pid })
  })
  
  app.listen(3000, () => {
    console.log(`Worker ${process.pid} started`)
  })
}

🛠️ 监控和调试 ​

1. 性能监控 ​

javascript
const perf_hooks = require('perf_hooks')

// 监控函数执行时间
function monitorPerformance(fn) {
  return async function(...args) {
    const start = perf_hooks.performance.now()
    try {
      const result = await fn.apply(this, args)
      const end = perf_hooks.performance.now()
      console.log(`Function ${fn.name} took ${end - start} milliseconds`)
      return result
    } catch (error) {
      const end = perf_hooks.performance.now()
      console.log(`Function ${fn.name} failed after ${end - start} milliseconds`)
      throw error
    }
  }
}

// 使用示例
const monitoredFunction = monitorPerformance(async (data) => {
  // 一些异步操作
  await new Promise(resolve => setTimeout(resolve, 1000))
  return data
})

2. 内存监控 ​

javascript
function logMemoryUsage() {
  const used = process.memoryUsage()
  console.log('Memory Usage:')
  console.log(`RSS: ${Math.round(used.rss / 1024 / 1024)} MB`)
  console.log(`Heap Total: ${Math.round(used.heapTotal / 1024 / 1024)} MB`)
  console.log(`Heap Used: ${Math.round(used.heapUsed / 1024 / 1024)} MB`)
  console.log(`External: ${Math.round(used.external / 1024 / 1024)} MB`)
}

// 定期监控内存使用
setInterval(logMemoryUsage, 30000) // 每30秒

📦 项目配置 ​

1. Package.json 优化 ​

json
{
  "name": "my-node-app",
  "version": "1.0.0",
  "main": "src/index.js",
  "scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "test": "jest",
    "build": "webpack --mode production",
    "pm2:start": "pm2 start ecosystem.config.js",
    "pm2:stop": "pm2 stop all"
  },
  "engines": {
    "node": ">=16.0.0",
    "npm": ">=8.0.0"
  }
}

2. PM2 配置 ​

javascript
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'src/index.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'development'
    },
    env_production: {
      NODE_ENV: 'production'
    },
    watch: false,
    max_memory_restart: '1G',
    error_file: './logs/err.log',
    out_file: './logs/out.log',
    log_file: './logs/combined.log',
    time: true
  }]
}

🧪 测试 ​

1. 单元测试 ​

javascript
const request = require('supertest')
const app = require('../src/app')

describe('API Tests', () => {
  test('GET /api/users should return users', async () => {
    const response = await request(app)
      .get('/api/users')
      .expect(200)
    
    expect(response.body).toHaveProperty('users')
    expect(Array.isArray(response.body.users)).toBe(true)
  })
  
  test('POST /api/users should create user', async () => {
    const userData = {
      name: 'John Doe',
      email: 'john@example.com'
    }
    
    const response = await request(app)
      .post('/api/users')
      .send(userData)
      .expect(201)
    
    expect(response.body).toHaveProperty('id')
    expect(response.body.name).toBe(userData.name)
  })
})

2. 压力测试 ​

javascript
const autocannon = require('autocannon')

async function runLoadTest() {
  const result = await autocannon({
    url: 'http://localhost:3000',
    connections: 100, // 并发连接数
    duration: 10, // 测试持续时间(秒)
    requests: [
      {
        method: 'GET',
        path: '/api/users'
      }
    ]
  })
  
  console.log('Load Test Results:')
  console.log(`Requests: ${result.requests.total}`)
  console.log(`Duration: ${result.duration}ms`)
  console.log(`Throughput: ${result.throughput} req/sec`)
  console.log(`Latency: ${result.latency.average}ms`)
}

runLoadTest()

🎯 最佳实践 ​

1. 错误处理 ​

javascript
// 全局错误处理
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error)
  process.exit(1)
})

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason)
  process.exit(1)
})

// 异步错误处理
async function safeAsyncOperation() {
  try {
    const result = await riskyOperation()
    return result
  } catch (error) {
    console.error('Operation failed:', error)
    // 记录错误但不中断程序
    return null
  }
}

2. 安全配置 ​

javascript
const helmet = require('helmet')
const rateLimit = require('express-rate-limit')

// 安全头设置
app.use(helmet())

// 速率限制
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15分钟
  max: 100 // 限制每个IP 15分钟内最多100个请求
})
app.use(limiter)

// CORS配置
app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'],
  credentials: true
}))

Node.js 让后端开发更高效! 🚀