Skip to content

PM2 部署 Node.js 项目

一、核心要点速览

💡 核心考点

  • 快速部署: pm2 start app.js -i max
  • 集群模式: 利用多核 CPU,提升性能
  • 配置文件: ecosystem.config.js 标准化管理
  • Nginx 反向代理: 负载均衡和 SSL 终止
  • 开机自启: pm2 startup + pm2 save

二、快速部署

1. 简单启动

bash
# ========== 基本命令 ==========
cd /path/to/your/node-app

# 单进程启动(开发环境)
pm2 start app.js

# 集群模式(推荐生产环境)
pm2 start app.js -i max

# 指定名称和参数
pm2 start app.js --name "my-api" -i 4 --max-memory-restart 500M


# ========== 保存配置 ==========
# 保存进程列表
pm2 save

# 生成开机自启配置
pm2 startup
# 复制输出的命令并执行(需要 sudo)

# 验证
pm2 list
pm2 monit

2. 集群模式优势

┌──────────────────────────────────────────────────────────┐
│              集群模式性能优化                             │
└──────────────────────────────────────────────────────────┘

CPU 核心利用:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
单进程模式:
  ┌─────────────────────────────┐
  │     Single Process          │
  │     (只用 1 个 CPU 核心)       │
  └─────────────────────────────┘
  CPU 利用率:~25% (4 核 CPU)

集群模式 (-i max):
  ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
  │ CPU │ │ CPU │ │ CPU │ │ CPU │
  │  0  │ │  1  │ │  2  │ │  3  │
  ├─────┤ ├─────┤ ├─────┤ ├─────┤
  │App 1│ │App 2│ │App 3│ │App 4│
  └─────┘ └─────┘ └─────┘ └─────┘
  CPU 利用率:~100% ✓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

最佳实践:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 根据 CPU 核心数设置实例
pm2 start app.js -i max

# 或手动指定
pm2 start app.js -i 4

# 动态缩放
pm2 scale api +2  # 增加 2 个实例
pm2 scale api -1  # 减少 1 个实例
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

三、完整部署流程

1. 步骤详解

bash
# ========== 步骤 1: 准备项目 ==========
cd /var/www/my-node-app

# 安装依赖
npm ci --only=production

# 创建日志目录
mkdir -p logs


# ========== 步骤 2: 创建配置文件 ==========
cat > ecosystem.config.js << 'EOF'
module.exports = {
  apps: [{
    name: 'my-node-app',
    script: './dist/server.js',
    instances: 4,
    exec_mode: 'cluster',
    
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    error_file: './logs/error.log',
    out_file: './logs/out.log',
    
    max_memory_restart: '1G',
    autorestart: true,
    max_restarts: 10,
    min_uptime: '10s'
  }]
}
EOF


# ========== 步骤 3: 启动应用 ==========
pm2 start ecosystem.config.js

# 验证
pm2 status
pm2 logs my-node-app


# ========== 步骤 4: 配置 Nginx ==========
cat > /etc/nginx/sites-available/my-app << 'EOF'
server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
EOF

ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/
nginx -t
systemctl restart nginx


# ========== 步骤 5: 配置防火墙 ==========
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

2. 项目结构示例

/var/www/my-node-app/
├── package.json
├── ecosystem.config.js      # PM2 配置
├── .env                     # 环境变量
├── logs/                    # 日志目录
│   ├── error.log
│   └── out.log

├── src/                     # 源代码
│   ├── index.js
│   ├── app.js
│   └── routes/

├── dist/                    # 构建输出
│   └── server.js

└── node_modules/            # 依赖

四、不同框架的部署

1. Express 项目

javascript
// app.js
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000

app.get('/', (req, res) => {
  res.send(`Hello from worker ${process.pid}`)
})

app.get('/health', (req, res) => {
  res.json({ 
    status: 'ok',
    pid: process.pid,
    uptime: process.uptime()
  })
})

// PM2 集群模式下不需要手动处理 cluster
// PM2 会自动管理

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})
javascript
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'express-app',
    script: './app.js',
    instances: 4,
    exec_mode: 'cluster',
    
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    
    max_memory_restart: '500M',
    autorestart: true
  }]
}

2. Koa 项目

javascript
// src/app.js
const Koa = require('koa')
const app = new Koa()

app.use(async ctx => {
  ctx.body = `Hello from Koa (PID: ${process.pid})`
})

const port = process.env.PORT || 3000
app.listen(port, () => {
  console.log(`Koa app listening on ${port}`)
})
javascript
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'koa-app',
    script: './src/app.js',
    instances: 4,
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    }
  }]
}

3. NestJS 项目

typescript
// main.ts
import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'

async function bootstrap() {
  const app = await NestFactory.create(AppModule)
  const port = process.env.PORT || 3000
  await app.listen(port)
  console.log(`NestJS application listening on ${port}`)
}

bootstrap()
javascript
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'nestjs-app',
    script: './dist/main.js',
    instances: 4,
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production'
    }
  }]
}

五、性能优化

1. 内存管理

javascript
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'memory-optimized-app',
    script: './app.js',
    instances: 4,
    exec_mode: 'cluster',
    
    // 内存限制
    max_memory_restart: '500M',  // 超过 500M 自动重启
    
    // Node 堆内存配置
    interpreter_args: '--max-old-space-size=4096',
    
    // 垃圾回收优化
    node_args: [
      '--max-old-space-size=4096',
      '--max-new-space-size=2048',
      '--gc-interval=100'
    ],
    
    // 重启策略
    autorestart: true,
    max_restarts: 10,
    min_uptime: '10s',
    restart_delay: 4000
  }]
}

2. 日志优化

javascript
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'logging-optimized-app',
    script: './app.js',
    
    // 日志格式
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    
    // 日志文件
    error_file: './logs/error-logs/error.log',
    out_file: './logs/out-logs/out.log',
    
    // 合并日志(集群模式)
    merge_logs: true,
    
    // 日志级别过滤
    log_level: 'info',  // debug, info, warn, error
  }]
}

// 安装日志轮转插件
pm2 install pm2-logrotate

// 配置日志轮转
pm2 set pm2-logrotate:max_size 10M      # 最大 10MB
pm2 set pm2-logrotate:retain 7          # 保留 7 个文件
pm2 set pm2-logrotate:compress true     # 压缩旧日志

六、监控与告警

1. 实时监控

bash
# 实时监控面板
pm2 monit

# 显示内容:
# ┌──────────────────────────────────────┐
# │ PM2 Monitoring                       │
# ├──────────────────────────────────────┤
# │ my-app                               │
# │ CPU: 15%  Memory: 256MB              │
# │ Status: online  Uptime: 2d 5h        │
# └──────────────────────────────────────┘

2. 健康检查

javascript
// monitor.js
const axios = require('axios')

async function checkHealth() {
  try {
    const response = await axios.get('http://localhost:3000/health')
    
    if (response.data.status !== 'ok') {
      console.error('Health check failed!')
      process.exit(1)
    }
    
    console.log('Health check passed')
  } catch (error) {
    console.error('Health check error:', error.message)
    process.exit(1)
  }
}

// 每分钟检查一次
setInterval(checkHealth, 60000)
checkHealth()

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'monitor',
    script: './monitor.js',
    instances: 1,
    cron_restart: '0 * * * *'  // 每小时重启
  }]
}

七、常见问题解决

1. 启动失败

bash
# 问题 1: 权限错误
sudo chown -R $USER:$USER /path/to/app
chmod +x app.js

# 问题 2: 端口被占用
lsof -i :3000
kill -9 <PID>

# 或修改配置
env: {
  PORT: 3001  # 改用其他端口
}

# 问题 3: Node 版本不兼容
node --version
nvm install 18
nvm use 18

2. 内存泄漏

bash
# 诊断
pm2 monit  # 观察内存增长

# 临时解决
pm2 restart all

# 永久解决:配置自动重启
max_memory_restart: '500M'

# 深度分析
pm2 trigger @pm2/io-agent heap:snapshot

3. 集群会话丢失

javascript
// 解决方案:使用外部 session 存储
const session = require('express-session')
const RedisStore = require('connect-redis')(session)

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: 'your-secret'
}))

八、面试标准回答

使用 PM2 部署 Node.js 项目非常简单高效

基本步骤是:

  1. 安装依赖后,使用 pm2 start app.js -i max 集群模式启动
  2. 或使用 ecosystem.config.js 配置文件标准化管理
  3. 配合 Nginx 反向代理实现负载均衡和 SSL 终止
  4. 执行 pm2 savepm2 startup 配置开机自启

集群模式的优势是可以充分利用多核 CPU,将单进程应用的 CPU 利用率从 25% 提升到 100%,并且支持零停机重启。

性能优化方面,我会:

  • 配置内存限制防止内存泄漏(max_memory_restart)
  • 设置日志轮转避免磁盘占满
  • 使用 Node 参数优化垃圾回收
  • 配置健康检查自动监控

实际项目中,我经常部署 Express、Koa、NestJS 等框架的应用,PM2 都能很好地管理,提供进程守护、日志收集、监控告警等企业级功能。


九、记忆口诀

部署 Node 歌诀:

PM2 部署很简单,
-i max 来启动。
集群模式性能好,
多核 CPU 全用上!

配置文件写好,
ecosystem 不能少。
Nginx 反代配,
开机自启要记牢!

内存限制要设好,
日志轮转定期搞。
监控面板实时看,
生产稳定没烦恼!

十、推荐资源


十一、总结一句话

  • 快速部署: pm2 start -i max = 一行命令搞定 🚀
  • 集群模式: 多核利用 + 零停机 = 性能提升关键
  • 配置文件: ecosystem.config.js = 标准化必备
  • 监控优化: 内存限制 + 日志轮转 = 生产稳定保障 🎯
最近更新