当前位置: 首页
AI教程
Node.js多进程集群部署,别让单进程扛整机

Node.js多进程集群部署,别让单进程扛整机

热心网友 时间:2026-07-01
转载

Node.js多进程和Cluster集群部署,别让一个进程扛完整台机器

Node.js 的单进程模型在理解上非常直观,但在生产环境中踩坑的姿势也相当丰富。

Node.js多进程和 Cluster 集群部署,别让一个进程扛完整台机器

想象一下:你在一台 8 核机器上运行一个 Express 服务,没有做任何特殊处理。真正干活的 JavaScript 引擎只有一个进程。CPU 一号核心已经累垮了,而旁边的几个核心却悠闲得像在围观。线上流量一旦上来,表象就很诡异:机器整体 CPU 看起来并不高,但接口的 p99 延迟已经开始剧烈抖动。

这篇文章专门讲解 Node.js 的多进程方案和 Cluster 集群部署。环境采用 Node.js 24 与 Express 5.2.1。我们先使用 Node 官方 cluster 模块搭建一个可运行的示例,然后讨论它的边界在哪里,以及为什么生产环境中很多团队最终选择使用 PM2、systemd、Docker 或 Kubernetes 来管理进程。

Cluster 解决的核心问题

Node 官方文档对 cluster 的描述非常直白:它能够创建一组子进程,并且这些子进程可以共享同一个服务器端口。

这里的关键词是——进程。

Cluster 不是线程池,也不是把一个请求拆给多个核心并行计算。它的工作方式更像这样:主进程负责启动 worker,多个 worker 都监听同一个端口,请求进入后,由主进程分发给其中一个 worker 去处理。

这样做直接带来两个好处:

  • 多核 CPU 终于能被充分利用起来。
  • 某个 worker 崩溃后,主进程可以立刻启动一个新的。

代价也很现实:进程之间内存不共享。你存放在内存里的登录态、计数器、缓存,每个 worker 都各自有一份。一旦上了多进程,就千万别再将进程内存当作全局真理。

一个最小可运行的 Cluster 服务

首先安装 Express:

mkdir node-cluster-demo
cd node-cluster-demo
npm init -y
npm install express

server.js

const cluster = require('node:cluster')
const os = require('node:os')
const process = require('node:process')
const express = require('express')

const port = Number(process.env.PORT || 3000)
const workerCount = Number(process.env.WORKERS || os.a vailableParallelism())

if (cluster.isPrimary) {
  console.log(`primary ${ process.pid} is running`)
  console.log(`starting ${ workerCount} workers`)
  for (let i = 0; i < workerCount; i  ) {
    cluster.fork()
  }
  cluster.on('exit', (worker, code, signal) => {
    console.error(`worker ${ worker.process.pid} died`, {code, signal })
    cluster.fork()
  })
} else {
  const app = express()
  app.get('/health', (req, res) => {
    res.json({ ok: true, pid: process.pid,})
  })
  app.get('/cpu', (req, res) => {
    const startedAt = Date.now()
    while (Date.now() - startedAt < 80) {
      Math.sqrt(Math.random())
    }
    res.json({ ok: true, pid: process.pid,})
  })
  app.listen(port, () => {
    console.log(`worker ${ process.pid} listening on http://localhost:${ port}`)
  })
}

启动服务:

node server.js

多请求几次:

curl http://localhost:3000/health
curl http://localhost:3000/health
curl http://localhost:3000/health

你会看到返回的 pid 可能不同——说明请求被分配到了不同的 worker 进程上。

这里特意用了 os.a vailableParallelism(),而不是以前习惯的 os.cpus().length。Node 官方在 os.cpus() 文档里也曾提醒过,不应拿它来计算应用可用并行度,推荐直接使用 os.a vailableParallelism()

生产代码不能只会 fork

上面的代码能运行,但离生产环境还有好几步。至少需要处理优雅退出:

function createApp() {
  const app = express()
  app.get('/health', (req, res) => {
    res.json({ok: true, pid: process.pid })
  })
  return app
}

if (cluster.isPrimary) {
  for (let i = 0; i < workerCount; i  ) {
    cluster.fork()
  }
  cluster.on('exit', (worker, code, signal) => {
    if (worker.exitedAfterDisconnect) { return }
    console.error(`worker ${ worker.process.pid} crashed`, {code, signal })
    cluster.fork()
  })
} else {
  const app = createApp()
  const server = app.listen(port)
  process.on('SIGTERM', () => {
    server.close(() => {
      process.exit(0)
    })
    setTimeout(() => {
      process.exit(1)
    }, 10_000).unref()
  })
}

server.close() 会停止接收新连接,等已有的连接处理完成后再退出。外面再加一个 10 秒的兜底,是为了防止某些长连接或异常请求导致进程永远退不掉。

主进程里也别无脑重启所有退出的 worker。worker.exitedAfterDisconnect 这个属性可以帮助你区分“主动要求它退出”和“它意外崩溃”。这在滚动重启时尤其有用。

状态别放在进程内存里

这是 Cluster 最容易踩坑的地方。

假设你写了一个简单计数器:

let counter = 0
app.post('/count', (req, res) => {
  counter  = 1
  res.json({counter, pid: process.pid })
})

单进程时它看起来没问题。多进程后,每个 worker 都有自己的 counter。请求打到 worker A,counter 是 10;下一个请求打到 worker B,counter 可能是 3。你以为自己写了全局计数器,实际上写了 N 个局部计数器。

登录态也一样。不要把 session 存在进程内存里,然后指望 Cluster 替你同步。应该放到 Redis、数据库,或者使用无状态 token。进程内缓存也要接受一个现实:每个 worker 都会各自缓存一份,命中率和内存占用都会受到影响。

曾经见过一个后台系统,上了 Cluster 之后验证码偶发校验失败。原因很朴实:验证码存在内存 Map 里,生成请求落到 worker 1,校验请求落到 worker 3,自然找不到了。

负载均衡不是魔法

Node cluster 支持两种分发方式。官方文档提到,除 Windows 外,默认是 round-robin,由主进程接收连接再分发给 worker。另一种方式是主进程创建监听 socket 后交给 worker,由 worker 自己 accept。

日常业务一般不用手动修改 cluster.schedulingPolicy。真正需要关心的是:worker 之间的负载可能仍然不均匀。

原因有很多:

  • 请求耗时不同,慢请求会长期占用某个 worker
  • 长连接(比如 WebSocket)会让连接长时间停留在某个 worker 上
  • CPU 密集逻辑会阻塞单个 worker 的 event loop

所以 Cluster 并不是性能银弹。它只是让你把请求分散到多个进程。如果某个接口本身写得很重,多进程能缓解,但不能从根本上解决问题。

多进程下日志和监控要带 pid

上了 Cluster 之后,日志里必须带上 pid 或 worker id:

logger.info('request finished', {
  pid: process.pid,
  workerId: cluster.worker?.id,
  method: req.method,
  path: req.originalUrl,
  status: res.statusCode,
})

否则你看到一段错误日志,很难判断是不是某一个 worker 持续出问题。比如 worker 4 内存一直上涨,最后反复重启。总览日志里只看到“进程重启了”,却看不到是哪一个,定位起来非常困难。

监控也一样。除了进程整体指标,我建议给每个 worker 都打上:

  • RSS、heapUsed
  • event loop delay
  • 请求数和错误数
  • 重启次数

多进程系统最怕平均值。平均 CPU 不高,不代表每个 worker 都健康;平均内存正常,也可能其中一个 worker 正在泄漏。

Cluster 和 PM2、容器怎么取舍

如果只是想理解原理,Node 内置 cluster 完全够用。

如果是生产部署,我的建议是按环境选择:

  • 传统服务器:可以用 PM2 的 cluster mode 或 systemd 管理多个进程。PM2 省心,日志、重启、进程列表都有现成命令。systemd 更贴近系统层,适合不想引入额外 Node 进程管理工具的团队。
  • Docker / Kubernetes 环境:我更倾向于一个容器只跑一个 Node 进程,然后通过多个副本来扩容。进程重启、健康检查、滚动发布、日志采集都交给平台。也可以在容器内再开 Cluster,但这样会让资源限制、优雅退出、监控粒度变得复杂。不是不能做,只是要有明确的理由。
  • 本地开发和小型内网服务:直接用 cluster 也够。但别把它当成完整的进程平台——它不负责日志采集、发布编排、健康检查、限流熔断,也不会替你处理共享状态。

什么场景不适合只靠 Cluster

下面几种情况,纯 Cluster 往往搞不定:

  • CPU 重任务:Cluster 能把请求分到多个进程,但单个请求里的 CPU 计算还是会堵住对应 worker。重计算更适合 Worker Threads、任务队列,或者拆成独立服务。
  • 大量 WebSocket 长连接:连接会固定在某个 worker 上,负载均衡和会话管理需要额外设计。多实例部署时还要考虑消息广播和房间状态。
  • 强依赖本地内存状态的应用:比如用本地 Map 存 session、验证码、临时任务状态。先把状态外置,再谈多进程。
  • 超短任务但日志极重的服务:进程多了,日志竞争和 IO 压力也会上来。这时要先控制日志量。

收尾

Cluster 的价值很朴素:让 Node 服务用上多核,并且给 worker 崩溃后的恢复留一个入口。

但它也会逼你面对几个工程事实:

  • 进程内存不是共享状态
  • 日志和监控必须能区分 worker
  • 优雅退出要自己处理
  • 多进程只能缓解单进程瓶颈,不能修好糟糕的同步代码

我的建议是:先用 cluster 把多进程模型跑明白,再根据部署环境决定交给谁管理。传统机器上用 PM2 或 systemd,容器环境交给 Kubernetes 或编排平台。无论选择哪条路,都别让一个 Node 进程孤零零扛完整台机器。

参考来源

  • Node.js cluster 官方文档:cluster 工作模型、cluster.isPrimarycluster.fork()exit 事件、调度策略,采集于 2026-06-29
  • Node.js os 官方文档:os.a vailableParallelism()os.cpus() 的使用建议,采集于 2026-06-29
  • Node.js process 官方文档:SIGTERM、进程事件与退出处理,采集于 2026-06-29
  • npm 元数据:express@5.2.1,采集于 2026-06-29
来源:https://developer.aliyun.com/article/1744477

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
内网RPA离线部署从依赖打包到7×24无人值守踩坑与避坑方案

内网RPA离线部署从依赖打包到7×24无人值守踩坑与避坑方案

这三年,内网RPA项目接了不下二十个。每次开局都像闯关——断网、缺依赖、多机同步、定时执行、批量分发、源码保护、AI离线化,八个坑一个比一个深。今天把这些实战经验整理出来,希望能帮正在内网搞自动化的兄弟们少踩点雷。 一、内网无网络环境怎么部署RPA流程:先搞清楚什么叫“真离线” 很多工具宣传“支持本

时间:2026-07-02 12:28
水利工程师用WorkBuddy写洪水报告效率提升3倍

水利工程师用WorkBuddy写洪水报告效率提升3倍

WorkBuddy开发者分享季 水利工程师AI提效实战:用WorkBuddy撰写洪水影响评价报告,效率提升3倍 WorkBuddy 效率 人工智能 开发工具 一、我是谁,为什么需要AI 先介绍一下自己——我是一名水利工程师,在湖南长沙的一家小型水利设计公司任职。当前行业环境不太

时间:2026-07-02 12:27
日志服务数据加工规则洞察仪表盘使用指南

日志服务数据加工规则洞察仪表盘使用指南

数据加工诊断仪表盘 想实时掌握日志服务加工功能的运行状态?直接从加工列表页点击那个“规则洞察”按钮,仪表盘就会立刻呈现出来。入口就在那儿,不绕弯子。 跳转后,你可以按作业名称、实例ID或源LogStore来筛选任务状态。比如下边这张图,展示的是当前实例ID(90c9d47714dbb807d47c1

时间:2026-07-02 12:27
基于RFID的固定资产管理系统技术架构与工程实践

基于RFID的固定资产管理系统技术架构与工程实践

固定资产管理难题是众多企事业单位的普遍困扰,资产数量动辄数千件,且广泛分布于不同部门、楼层乃至园区。传统人工盘点方式在工程维度上始终面临三大关键瓶颈:采集效率低下、数据闭环中断、状态同步滞后。使用条码枪逐一扫描标签,识别距离通常不超过30厘米,操作人员需逐个寻找并扫描,盘点效率完全受限于人力。面对5

时间:2026-07-02 12:27
WorkBuddy实战用AI搭建A股智能盯盘助手省心高效

WorkBuddy实战用AI搭建A股智能盯盘助手省心高效

炒股的朋友们想必都深有体会——每天重复盯盘、查行情、分析板块轮动,这一整套流程下来耗费大量精力。手动翻查数据不仅身心俱疲,还很容易错过关键买卖节点。今天我们就来聊聊如何打造一款趁手的盯盘工具,借助AI替你分担这些重复性工作。 背景:盯盘的核心痛点 股民都有同感——每天不只要查询单只股票的实时行情,还

时间:2026-07-02 12:27
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜