Node.js生产环境完整部署指南:PM2集群、Nginx代理与健康监控实战

Node.js单进程架构无法利用多核CPU,且进程崩溃后无法自动恢复。PM2(Process Manager 2)解决了这两个问题:集群模式利用所有CPU核心,守护进程在崩溃后自动重启。本文给出完整的生产部署方案。

一、生产环境准备

<code"># 安装Node.js LTS版本(通过nvm管理版本)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc

nvm install --lts
nvm use --lts
nvm alias default node

node --version   # v20.x.x
npm --version

# 全局安装PM2
npm install -g pm2

# 验证PM2
pm2 --version

二、PM2 ecosystem.config.js 完整配置

<code">// ecosystem.config.js
module.exports = {
    apps: [
        {
            // ========== 主API应用 ==========
            name: 'api-server',
            script: './src/server.js',

            // 集群模式:充分利用所有CPU核心
            instances: 'max',      // 或指定数字:4
            exec_mode: 'cluster',

            // 自动重启配置
            autorestart: true,
            watch: false,          // 生产环境不监听文件变化
            max_restarts: 10,      // 最多重启10次(防止故障循环)
            restart_delay: 3000,   // 重启前等待3秒

            // 内存超限自动重启
            max_memory_restart: '500M',

            // 环境变量(生产环境)
            env_production: {
                NODE_ENV: 'production',
                PORT: 3000,
            },
            // 环境变量(开发环境)
            env_development: {
                NODE_ENV: 'development',
                PORT: 3001,
                DEBUG: '*',
            },

            // 日志配置
            error_file: '/var/log/pm2/api-error.log',
            out_file: '/var/log/pm2/api-out.log',
            log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
            merge_logs: true,      // 合并所有实例的日志

            // 优雅关闭(接收SIGINT后等待请求处理完毕)
            kill_timeout: 5000,    // 最多等待5秒
            listen_timeout: 8000,  // 等待8秒让应用完成启动

            // 健康检查
            wait_ready: true,      // 等待process.send('ready')信号
        },

        {
            // ========== Worker进程 ==========
            name: 'queue-worker',
            script: './src/worker.js',
            instances: 2,
            exec_mode: 'fork',     // Worker不需要集群模式
            autorestart: true,
            max_memory_restart: '300M',
            env_production: {
                NODE_ENV: 'production',
                WORKER_CONCURRENCY: 5,
            },
            error_file: '/var/log/pm2/worker-error.log',
            out_file: '/var/log/pm2/worker-out.log',
        },
    ],
};

三、应用代码:支持优雅关闭

<code">// src/server.js
const express = require('express');
const app = express();

// 健康检查端点(用于负载均衡和监控)
app.get('/health', (req, res) => {
    res.json({
        status: 'ok',
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        timestamp: new Date().toISOString(),
    });
});

// 就绪检查端点(K8s readinessProbe)
app.get('/ready', async (req, res) => {
    try {
        // 检查数据库连接
        await db.ping();
        // 检查Redis连接
        await redis.ping();
        res.json({ status: 'ready' });
    } catch (err) {
        res.status(503).json({ status: 'not ready', error: err.message });
    }
});

// 你的业务路由
app.use('/api', require('./routes'));

const server = app.listen(process.env.PORT || 3000, () => {
    console.log(`API服务器运行在端口 ${process.env.PORT || 3000}`);

    // 通知PM2应用已就绪(配合wait_ready: true)
    if (process.send) {
        process.send('ready');
    }
});

// ============ 优雅关闭 ============
const gracefulShutdown = (signal) => {
    console.log(`收到 ${signal} 信号,开始优雅关闭...`);

    server.close(async () => {
        console.log('HTTP服务器已关闭');

        // 关闭数据库连接
        await db.end();
        // 关闭Redis连接
        await redis.quit();

        console.log('所有连接已关闭,进程退出');
        process.exit(0);
    });

    // 强制关闭超时(PM2 kill_timeout设置的时间)
    setTimeout(() => {
        console.error('优雅关闭超时,强制退出');
        process.exit(1);
    }, 4000);
};

process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));

四、PM2常用管理命令

<code"># 启动(生产环境)
pm2 start ecosystem.config.js --env production

# 零停机重载(集群模式下,逐个重启实例)
pm2 reload api-server

# 零停机重启(等待ready信号)
pm2 reload ecosystem.config.js --update-env

# 查看所有进程状态
pm2 list

# 实时监控(CPU/内存/请求数)
pm2 monit

# 查看日志
pm2 logs api-server
pm2 logs api-server --lines 200

# 清除日志
pm2 flush api-server

# 保存当前进程列表(重启服务器后自动恢复)
pm2 save
pm2 startup   # 生成开机自启命令,按提示执行

# 删除进程
pm2 delete api-server

# 查看详细信息
pm2 show api-server

五、Nginx反向代理配置

<code">upstream api_cluster {
    least_conn;

    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;

    keepalive 64;    # 保持长连接池,提升性能
}

server {
    listen 443 ssl http2;
    server_name api.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;

    # 安全响应头
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Strict-Transport-Security "max-age=31536000" always;

    location / {
        proxy_pass http://api_cluster;
        proxy_http_version 1.1;

        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_set_header Connection "";    # 启用keep-alive

        proxy_connect_timeout 10s;
        proxy_read_timeout 60s;

        # 请求缓冲(Node.js不需要,让Nginx快速转发)
        proxy_buffering off;
        proxy_request_buffering off;
    }

    # 健康检查端点不记录日志(减少日志噪声)
    location = /health {
        proxy_pass http://api_cluster;
        access_log off;
    }
}

六、PM2日志管理

<code"># 安装PM2日志轮转模块
pm2 install pm2-logrotate

# 配置(保留7天日志,每个文件最大50MB)
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD_HH-mm-ss
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'  # 每天轮转

七、性能调优

<code"># Node.js内存调优(针对V8引擎)
# 在package.json的scripts中:
{
  "scripts": {
    "start": "node --max-old-space-size=512 src/server.js"
  }
}

# 或在ecosystem.config.js中:
{
    node_args: '--max-old-space-size=512'
}

# 开启libuv线程池(CPU密集型任务,如加密)
# 默认4个线程,CPU核心数多时可以增加
{
    env: {
        UV_THREADPOOL_SIZE: 8
    }
}

八、总结

PM2集群模式 + 优雅关闭 + Nginx反向代理,是Node.js生产部署的标准架构。集群模式让4核服务器的Node.js吞吐量提升约4倍,零停机重载让代码更新不影响在线用户。IDC.Net的香港VPS4核8G配置配合PM2集群,是运行中高流量Node.js API服务的理想选择。

THE END