跳到正文
前端知识库
后端与网络

Node.js Cluster 模块详解

Node.js 是单线程运行的,这意味着默认情况下只能利用一个 CPU 核心。对于多核服务器来说,这是巨大的资源浪费。Cluster 模块允许创建多个子进程(工作进程),充分利用多核 CPU 的性能,同时保持代码的简洁性。理解 Cluster 模块的工作原理对于构建高性能、高可用的 Node.js 应用至关重要。

10 分钟

Node.js Cluster 模块详解

1. 问题解析

Node.js 是单线程运行的,这意味着默认情况下只能利用一个 CPU 核心。对于多核服务器来说,这是巨大的资源浪费。Cluster 模块允许创建多个子进程(工作进程),充分利用多核 CPU 的性能,同时保持代码的简洁性。理解 Cluster 模块的工作原理对于构建高性能、高可用的 Node.js 应用至关重要。

2. 核心概念

2.1 Node.js 单线程模型

┌─────────────────────────────────────────┐
│           单线程 Node.js 进程            │
│  ┌─────────────────────────────────┐    │
│  │         JavaScript 代码          │    │
│  │        (单线程执行)              │    │
│  └─────────────────────────────────┘    │
│                   ↓                     │
│  ┌─────────────────────────────────┐    │
│  │           libuv 线程池           │    │
│  │  ┌─────┐ ┌─────┐ ┌─────┐ ┌────┐ │    │
│  │  │线程1│ │线程2│ │线程3│ │线程4│ │    │
│  │  └─────┘ └─────┘ └─────┘ └────┘ │    │
│  └─────────────────────────────────┘    │
│                   ↓                     │
│  ┌─────────────────────────────────┐    │
│  │      操作系统(多核 CPU)         │    │
│  │  ┌─────┐ ┌─────┐ ┌─────┐ ┌────┐ │    │
│  │  │核心1│ │核心2│ │核心3│ │核心4│ │    │
│  │  └─────┘ └─────┘ └─────┘ └────┘ │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

2.2 Cluster 多进程模型

┌─────────────────────────────────────────┐
│              主进程 (Master)             │
│         ┌──────────────────┐            │
│         │   负责调度管理     │            │
│         │   - 创建/重启子进程 │            │
│         │   - 负载均衡       │            │
│         │   - 进程间通信     │            │
│         └────────┬─────────┘            │
│                  │                      │
│    ┌─────────────┼─────────────┐        │
│    ↓             ↓             ↓        │
│ ┌──────┐    ┌──────┐    ┌──────┐       │
│ │Worker│    │Worker│    │Worker│       │
│ │  #1  │    │  #2  │    │  #3  │       │
│ └──┬───┘    └──┬───┘    └──┬───┘       │
└────┼───────────┼───────────┼───────────┘
     │           │           │
     └───────────┼───────────┘
                 ↓
         ┌───────────────┐
         │   共享端口     │
         │  (Round Robin) │
         └───────────────┘

2.3 进程间关系

角色 职责 数量
Master 进程管理、负载均衡、不处理业务 1
Worker 处理 HTTP 请求、执行业务逻辑 通常等于 CPU 核心数

3. 详细解答

3.1 Cluster 基础使用

const cluster = require('cluster');
const http = require('http');
const os = require('os');

const numCPUs = os.cpus().length;

if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);

  // 创建与 CPU 核心数相同的工作进程
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // 监听工作进程事件
  cluster.on('fork', (worker) => {
    console.log(`工作进程 ${worker.process.pid} 已创建`);
  });

  cluster.on('online', (worker) => {
    console.log(`工作进程 ${worker.process.pid} 已就绪`);
  });

  cluster.on('listening', (worker, address) => {
    console.log(`工作进程 ${worker.process.pid} 正在监听 ${address.port}`);
  });

  cluster.on('disconnect', (worker) => {
    console.log(`工作进程 ${worker.process.pid} 已断开连接`);
  });

  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出 (code: ${code}, signal: ${signal})`);

    // 自动重启工作进程
    console.log('正在创建新的工作进程...');
    cluster.fork();
  });

  // 主进程收到消息
  Object.values(cluster.workers).forEach(worker => {
    worker.on('message', (msg) => {
      console.log(`主进程收到来自 ${worker.process.pid} 的消息:`, msg);
    });
  });

} else {
  // 工作进程创建 HTTP 服务器
  const server = http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Hello from worker ${process.pid}\n`);

    // 模拟工作进程向主进程发送消息
    process.send({ cmd: 'notifyRequest', pid: process.pid });
  });

  server.listen(8000);

  console.log(`工作进程 ${process.pid} 已启动`);
}

3.2 进程间通信 (IPC)

const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  const workers = [];

  // 创建工作进程
  for (let i = 0; i < os.cpus().length; i++) {
    const worker = cluster.fork();
    workers.push(worker);

    // 接收工作进程消息
    worker.on('message', (msg) => {
      if (msg.cmd === 'getSharedData') {
        // 主进程查询共享数据后返回
        worker.send({
          cmd: 'sharedDataResponse',
          data: getSharedData(msg.key)
        });
      } else if (msg.cmd === 'broadcast') {
        // 向所有工作进程广播消息
        workers.forEach(w => {
          if (w.id !== worker.id) {
            w.send({
              cmd: 'broadcastMessage',
              from: worker.id,
              data: msg.data
            });
          }
        });
      }
    });
  }

  // 模拟共享数据存储
  const sharedData = new Map();
  function getSharedData(key) {
    return sharedData.get(key);
  }

} else {
  // 工作进程
  const http = require('http');

  // 接收主进程消息
  process.on('message', (msg) => {
    if (msg.cmd === 'sharedDataResponse') {
      console.log(`Worker ${process.pid} 收到共享数据:`, msg.data);
    } else if (msg.cmd === 'broadcastMessage') {
      console.log(`Worker ${process.pid} 收到广播:`, msg.data);
    }
  });

  const server = http.createServer((req, res) => {
    if (req.url === '/get-data') {
      // 向主进程请求共享数据
      process.send({ cmd: 'getSharedData', key: 'config' });
      res.end('Request sent to master');
    } else if (req.url === '/broadcast') {
      // 向所有工作进程广播
      process.send({ cmd: 'broadcast', data: { message: 'Hello all!' } });
      res.end('Broadcast sent');
    } else {
      res.end(`Worker ${process.pid}`);
    }
  });

  server.listen(8000);
}

3.3 负载均衡策略

const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  // 设置负载均衡策略
  // cluster.SCHED_NONE - 由操作系统决定(默认在 Windows 上)
  // cluster.SCHED_RR - Round Robin 轮询(默认在非 Windows 上)

  cluster.schedulingPolicy = cluster.SCHED_RR;

  console.log('负载均衡策略:', cluster.schedulingPolicy === cluster.SCHED_RR ? 'Round Robin' : 'None');

  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }

} else {
  const http = require('http');

  // 模拟不同处理时间的请求
  http.createServer(async (req, res) => {
    const delay = Math.random() * 1000;
    await sleep(delay);

    res.writeHead(200);
    res.end(JSON.stringify({
      worker: process.pid,
      delay: Math.round(delay)
    }));
  }).listen(8000);
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

3.4 优雅关闭与零停机部署

const cluster = require('cluster');
const http = require('http');
const os = require('os');

if (cluster.isMaster) {
  const workers = new Map();

  // 创建工作进程
  function createWorker() {
    const worker = cluster.fork();
    workers.set(worker.id, worker);

    worker.on('exit', (code, signal) => {
      workers.delete(worker.id);

      // 如果不是主动关闭,则重启
      if (signal !== 'SIGTERM') {
        console.log(`工作进程 ${worker.process.pid} 异常退出,正在重启...`);
        createWorker();
      }
    });

    return worker;
  }

  // 初始创建工作进程
  for (let i = 0; i < os.cpus().length; i++) {
    createWorker();
  }

  // 优雅重启所有工作进程
  function gracefulReload() {
    console.log('开始优雅重启...');

    const workerIds = Array.from(workers.keys());
    let index = 0;

    function restartNext() {
      if (index >= workerIds.length) {
        console.log('所有工作进程已重启');
        return;
      }

      const workerId = workerIds[index++];
      const worker = workers.get(workerId);

      if (worker) {
        console.log(`正在重启工作进程 ${worker.process.pid}...`);

        // 发送断开连接信号
        worker.disconnect();

        // 超时强制终止
        const timeout = setTimeout(() => {
          console.log(`工作进程 ${worker.process.pid} 超时,强制终止`);
          worker.kill('SIGTERM');
        }, 5000);

        worker.on('disconnect', () => {
          clearTimeout(timeout);
          console.log(`工作进程 ${worker.process.pid} 已断开连接`);
        });

        // 创建新工作进程
        setTimeout(() => {
          createWorker();
          restartNext();
        }, 1000);
      }
    }

    restartNext();
  }

  // 监听信号进行优雅重启
  process.on('SIGUSR2', gracefulReload);

  // 优雅关闭
  process.on('SIGTERM', () => {
    console.log('主进程收到 SIGTERM,开始优雅关闭...');

    workers.forEach(worker => {
      worker.send({ cmd: 'shutdown' });
      worker.disconnect();
    });

    // 超时后强制退出
    setTimeout(() => {
      console.log('强制退出');
      process.exit(1);
    }, 10000);
  });

} else {
  let server;
  let isShuttingDown = false;

  // 创建服务器
  server = http.createServer((req, res) => {
    if (isShuttingDown) {
      res.writeHead(503, { 'Connection': 'close' });
      res.end('Server is shutting down');
      return;
    }

    // 模拟请求处理
    res.writeHead(200);
    res.end(`Response from worker ${process.pid}`);
  });

  server.listen(8000, () => {
    console.log(`Worker ${process.pid} 开始监听`);
  });

  // 处理来自主进程的消息
  process.on('message', (msg) => {
    if (msg.cmd === 'shutdown') {
      console.log(`Worker ${process.pid} 收到关闭信号`);
      isShuttingDown = true;

      // 关闭服务器,停止接受新连接
      server.close(() => {
        console.log(`Worker ${process.pid} 服务器已关闭`);

        // 等待现有连接处理完成
        setTimeout(() => {
          process.exit(0);
        }, 2000);
      });
    }
  });

  // 处理未捕获的异常
  process.on('uncaughtException', (err) => {
    console.error(`Worker ${process.pid} 未捕获异常:`, err);

    // 优雅关闭
    server.close(() => {
      process.exit(1);
    });

    // 超时强制退出
    setTimeout(() => {
      process.exit(1);
    }, 5000);
  });
}

4. 深入理解

4.1 Cluster 底层原理

const cluster = require('cluster');
const net = require('net');

// Cluster 底层使用 child_process.fork() 创建子进程
// 并通过 IPC 通道进行通信

if (cluster.isMaster) {
  console.log('Master 进程分析:');
  console.log('- 负责创建 Worker 进程');
  console.log('- 监听 Worker 事件(online, listening, disconnect, exit)');
  console.log('- 处理 Worker 间负载均衡');

  // 查看 cluster 模块内部实现
  console.log('Worker 列表:', cluster.workers);

  const worker = cluster.fork();

  // 向 Worker 发送消息
  worker.send({ hello: 'worker' });

  // 接收 Worker 消息
  worker.on('message', (msg) => {
    console.log('收到 Worker 消息:', msg);
  });

  // 断开 Worker 连接
  setTimeout(() => {
    worker.disconnect();
  }, 5000);

} else {
  console.log(`Worker ${process.pid} 分析:`);
  console.log('- 独立的 Node.js 进程');
  console.log('- 有自己的 V8 实例和事件循环');
  console.log('- 内存不共享');
  console.log('- 通过 IPC 与 Master 通信');

  // Worker 接收 Master 消息
  process.on('message', (msg) => {
    console.log('收到 Master 消息:', msg);

    // 回复 Master
    process.send({ reply: 'hello master', pid: process.pid });
  });

  // 创建服务器
  const server = net.createServer((socket) => {
    socket.end(`Handled by worker ${process.pid}\n`);
  });

  server.listen(8000, () => {
    console.log(`Worker ${process.pid} 监听端口 8000`);
  });
}

4.2 进程间内存共享方案

const cluster = require('cluster');

/**
 * 由于 Worker 间内存不共享,需要使用外部存储
 * 方案:Redis、共享内存、数据库
 */

// 方案 1: 使用 Redis 共享数据
const Redis = require('ioredis');

class SharedState {
  constructor() {
    this.redis = new Redis();
    this.localCache = new Map();
  }

  async get(key) {
    // 先查本地缓存
    if (this.localCache.has(key)) {
      return this.localCache.get(key);
    }

    // 查 Redis
    const value = await this.redis.get(key);
    if (value) {
      this.localCache.set(key, value);
    }
    return value;
  }

  async set(key, value, ttl = 3600) {
    this.localCache.set(key, value);
    await this.redis.setex(key, ttl, value);
  }

  // 发布订阅模式实现跨进程通知
  subscribe(channel, callback) {
    const subscriber = new Redis();
    subscriber.subscribe(channel);
    subscriber.on('message', (ch, message) => {
      callback(JSON.parse(message));
    });
  }

  publish(channel, message) {
    this.redis.publish(channel, JSON.stringify(message));
  }
}

// 方案 2: 使用共享内存(仅限于同一台机器)
const SharedArrayBuffer = require('worker_threads').SharedArrayBuffer;

// 注意:SharedArrayBuffer 主要用于 Worker Threads,
// Cluster 进程间需要使用其他 IPC 机制

// 方案 3: 使用数据库
const sharedDB = {
  async getCounter(name) {
    // 使用数据库事务保证原子性
    const result = await db.query(
      'UPDATE counters SET value = value + 1 WHERE name = ? RETURNING value',
      [name]
    );
    return result.rows[0].value;
  }
};

4.3 与 Worker Threads 对比

/**
 * Cluster vs Worker Threads
 *
 * Cluster:
 * - 多个独立进程
 * - 适合 I/O 密集型任务
 * - 进程崩溃不影响其他进程
 * - 内存不共享
 * - 适合 Web 服务器
 *
 * Worker Threads:
 * - 同一进程内的多个线程
 * - 适合 CPU 密集型任务
 * - 可以共享内存(SharedArrayBuffer)
 * - 一个线程崩溃可能导致整个进程崩溃
 * - 适合复杂计算
 */

// Worker Threads 示例
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

if (isMainThread) {
  // 主线程
  console.log('使用 Worker Threads 进行 CPU 密集型计算');

  const worker = new Worker(__filename, {
    workerData: { n: 40 } // 传递数据给 Worker
  });

  worker.on('message', (result) => {
    console.log('计算结果:', result);
  });

  worker.on('error', console.error);

} else {
  // Worker 线程
  function fibonacci(n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
  }

  const result = fibonacci(workerData.n);
  parentPort.postMessage(result);
}

// Cluster + Worker Threads 结合使用
// Cluster 处理 HTTP 请求,Worker Threads 处理 CPU 密集型任务
const cluster = require('cluster');
const { Worker } = require('worker_threads');

if (cluster.isMaster) {
  // Cluster Master 创建多个 Worker 进程
  for (let i = 0; i < require('os').cpus().length; i++) {
    cluster.fork();
  }
} else {
  // Cluster Worker 进程
  const http = require('http');

  http.createServer((req, res) => {
    if (req.url === '/compute') {
      // 使用 Worker Thread 进行计算
      const worker = new Worker('./compute-worker.js', {
        workerData: { n: 35 }
      });

      worker.on('message', (result) => {
        res.end(`Result: ${result}`);
      });

      worker.on('error', (err) => {
        res.statusCode = 500;
        res.end(`Error: ${err.message}`);
      });
    } else {
      res.end(`Hello from process ${process.pid}`);
    }
  }).listen(8000);
}

5. 最佳实践

5.1 生产级 Cluster 配置

const cluster = require('cluster');
const os = require('os');
const http = require('http');

const CONFIG = {
  // 工作进程数,通常等于 CPU 核心数
  workers: process.env.WORKERS || os.cpus().length,

  // 优雅关闭超时(毫秒)
  shutdownTimeout: 10000,

  // 进程重启间隔(毫秒)
  restartDelay: 1000,

  // 最大重启次数(防止无限重启)
  maxRestarts: 5
};

if (cluster.isMaster) {
  console.log(`Master ${process.pid} 启动`);

  const restartCount = new Map();

  // 创建工作进程
  for (let i = 0; i < CONFIG.workers; i++) {
    createWorker();
  }

  function createWorker() {
    const worker = cluster.fork();

    restartCount.set(worker.id, 0);

    worker.on('exit', (code, signal) => {
      const count = restartCount.get(worker.id) || 0;

      if (signal === 'SIGTERM' || code === 0) {
        console.log(`Worker ${worker.process.pid} 正常退出`);
        return;
      }

      if (count >= CONFIG.maxRestarts) {
        console.error(`Worker ${worker.process.pid} 重启次数过多,放弃重启`);
        return;
      }

      console.log(`Worker ${worker.process.pid} 退出,准备重启 (${count + 1}/${CONFIG.maxRestarts})`);

      setTimeout(() => {
        const newWorker = createWorker();
        restartCount.set(newWorker.id, count + 1);
      }, CONFIG.restartDelay);
    });

    return worker;
  }

  // 优雅重启
  process.on('SIGUSR2', () => {
    console.log('收到 SIGUSR2,开始优雅重启...');

    const workers = Object.values(cluster.workers);
    let index = 0;

    function restartNext() {
      if (index >= workers.length) return;

      const worker = workers[index++];

      worker.send({ cmd: 'graceful-shutdown' });
      worker.disconnect();

      const timeout = setTimeout(() => {
        worker.kill('SIGTERM');
      }, CONFIG.shutdownTimeout);

      worker.on('disconnect', () => {
        clearTimeout(timeout);
        createWorker();
        setTimeout(restartNext, CONFIG.restartDelay);
      });
    }

    restartNext();
  });

  // 优雅关闭
  process.on('SIGTERM', () => {
    console.log('收到 SIGTERM,开始优雅关闭...');

    Object.values(cluster.workers).forEach(worker => {
      worker.send({ cmd: 'graceful-shutdown' });
      worker.disconnect();
    });

    setTimeout(() => {
      console.log('强制退出');
      process.exit(1);
    }, CONFIG.shutdownTimeout);
  });

} else {
  // Worker 进程
  let server;
  let isShuttingDown = false;

  // 健康检查端点
  const healthChecks = {
    '/health': () => ({ status: 'ok', pid: process.pid }),
    '/ready': () => isShuttingDown ? null : { status: 'ready' }
  };

  server = http.createServer((req, res) => {
    // 健康检查
    if (healthChecks[req.url]) {
      const result = healthChecks[req.url]();
      if (result) {
        res.writeHead(200);
        res.end(JSON.stringify(result));
      } else {
        res.writeHead(503);
        res.end(JSON.stringify({ status: 'not ready' }));
      }
      return;
    }

    if (isShuttingDown) {
      res.writeHead(503, { 'Connection': 'close' });
      res.end('Server is shutting down');
      return;
    }

    // 业务逻辑
    res.writeHead(200);
    res.end(`Hello from ${process.pid}`);
  });

  server.listen(8000, () => {
    console.log(`Worker ${process.pid} 启动,监听端口 8000`);
  });

  // 处理关闭信号
  process.on('message', (msg) => {
    if (msg.cmd === 'graceful-shutdown') {
      isShuttingDown = true;

      server.close(() => {
        console.log(`Worker ${process.pid} 服务器已关闭`);
        process.exit(0);
      });

      setTimeout(() => {
        console.log(`Worker ${process.pid} 关闭超时`);
        process.exit(1);
      }, CONFIG.shutdownTimeout);
    }
  });

  // 错误处理
  process.on('uncaughtException', (err) => {
    console.error(`Worker ${process.pid} 未捕获异常:`, err);
    process.exit(1);
  });

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

5.2 PM2 集群模式原理

/**
 * PM2 是一个进程管理器,其集群模式基于 Node.js Cluster 模块
 * 但提供了更多功能:
 * - 自动负载均衡
 * - 零停机重载
 * - 日志管理
 * - 监控
 * - 进程守护
 */

// ecosystem.config.js - PM2 配置文件
module.exports = {
  apps: [{
    name: 'my-app',
    script: './app.js',

    // 集群模式
    exec_mode: 'cluster',

    // 实例数(0 = 使用所有 CPU)
    instances: 0,

    // 自动重启
    autorestart: true,

    // 内存限制(超过则重启)
    max_memory_restart: '1G',

    // 日志
    log_file: './logs/combined.log',
    out_file: './logs/out.log',
    error_file: './logs/error.log',

    // 环境变量
    env: {
      NODE_ENV: 'development'
    },
    env_production: {
      NODE_ENV: 'production'
    },

    // 监听文件变化(开发模式)
    watch: false,

    // 忽略的文件
    ignore_watch: ['node_modules', 'logs'],

    // 优雅关闭超时
    kill_timeout: 5000,

    // 监听端口(PM2 会自动分配)
    // 应用内使用 process.env.PORT

    // 合并日志(所有实例写入同一文件)
    merge_logs: true,

    // 日志日期格式
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
  }]
};

// PM2 常用命令
// pm2 start ecosystem.config.js
// pm2 reload my-app        # 零停机重载
// pm2 scale my-app +2      # 增加 2 个实例
// pm2 scale my-app 4       # 设置实例数为 4
// pm2 monit                # 监控
// pm2 logs                 # 查看日志

5.3 状态外化与 Session 共享

const cluster = require('cluster');
const session = require('koa-session');
const RedisStore = require('koa-redis');

/**
 * 在 Cluster 模式下,Session 必须存储在外部存储中
 * 不能依赖进程内存
 */

const Koa = require('koa');
const app = new Koa();

// 使用 Redis 存储 Session
app.keys = ['your-secret-key'];

app.use(session({
  store: new RedisStore({
    host: 'localhost',
    port: 6379
  }),
  key: 'koa:sess',
  maxAge: 86400000, // 1天
  httpOnly: true,
  secure: false
}, app));

// 其他需要共享的状态也使用 Redis
const redis = require('redis').createClient();

// 共享计数器
async function incrementCounter(name) {
  return await redis.incr(`counter:${name}`);
}

// 共享配置
async function getConfig(key) {
  return await redis.get(`config:${key}`);
}

// 分布式锁
async function acquireLock(lockName, timeout = 10000) {
  const token = Date.now().toString();
  const acquired = await redis.set(
    `lock:${lockName}`,
    token,
    'PX',
    timeout,
    'NX'
  );
  return acquired ? token : null;
}

async function releaseLock(lockName, token) {
  const current = await redis.get(`lock:${lockName}`);
  if (current === token) {
    await redis.del(`lock:${lockName}`);
  }
}

6. 面试要点

  1. 为什么需要 Cluster 模块知识点:Node.js 单线程模型

    • Node.js 单线程只能利用一个 CPU 核心
    • 多核服务器需要创建多个进程来充分利用资源
    • 提高应用吞吐量和可用性
  2. Master 和 Worker 的职责分工知识点:进程间关系

    • Master:进程管理、负载均衡、故障恢复、不处理业务请求
    • Worker:处理 HTTP 请求、执行业务逻辑
    • Master 和 Worker 通过 IPC 通信
  3. 负载均衡策略知识点:负载均衡策略

    • Round Robin(轮询):默认策略,依次分配请求
    • None:由操作系统决定(Windows 默认)
    • 可以通过 cluster.schedulingPolicy 设置
  4. 进程间通信方式知识点:进程间通信(IPC)

    • worker.send() / process.send():发送消息
    • worker.on('message') / process.on('message'):接收消息
    • 由于内存不共享,需要通过 IPC 或外部存储(Redis)共享数据
  5. Cluster 与 Worker Threads 的区别知识点:与 Worker Threads 对比

    • Cluster:多进程,适合 I/O 密集型,进程崩溃隔离
    • Worker Threads:多线程,适合 CPU 密集型,可共享内存
    • 可以结合使用:Cluster 处理 HTTP,Worker Threads 处理计算
  6. PM2 集群模式的优势知识点:PM2 集群模式原理

    • 基于 Cluster 模块,但提供更多功能
    • 零停机重载、自动重启、内存限制
    • 日志管理、监控、进程守护
    • 简化 Cluster 的使用
  7. 生产环境注意事项知识点:生产级 Cluster 配置知识点:状态外化与 Session 共享

    • Session 和状态必须外化到 Redis 等存储
    • 实现优雅关闭,避免请求中断
    • 设置进程重启限制,防止无限重启
    • 实现健康检查端点
    • 处理未捕获异常和 Promise 拒绝