在nodejs中创建cluster

简介: 在nodejs中创建cluster

目录



在nodejs中创建cluster


简介


在前面的文章中,我们讲到了可以通过worker_threads来创建新的线程,可以使用child_process来创建新的子进程。本文将会介绍如何创建nodejs的集群cluster。


cluster集群


我们知道,nodejs的event loop或者说事件响应处理器是单线程的,但是现在的CPU基本上都是多核的,为了充分利用现代CPU多核的特性,我们可以创建cluster,从而使多个子进程来共享同一个服务器端口。


也就是说,通过cluster,我们可以使用多个子进程来服务处理同一个端口的请求。


先看一个简单的http server中使用cluster的例子:


const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);
  // 衍生工作进程。
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 工作进程可以共享任何 TCP 连接。
  // 在本例子中,共享的是 HTTP 服务器。
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('你好世界\n');
  }).listen(8000);
  console.log(`工作进程 ${process.pid} 已启动`);
}


cluster详解


cluster模块源自于lib/cluster.js,我们可以通过cluster.fork()来创建子工作进程,用来处理主进程的请求。


cluster中的event


cluster继承自events.EventEmitter,所以cluster可以发送和接收event。


cluster支持7中event,分别是disconnect,exit,fork,listening,message,online和setup。


在讲解disconnect之前,我们先介绍一个概念叫做IPC,IPC的全称是Inter-Process Communication,也就是进程间通信。


IPC主要用来进行主进程和子进程之间的通信。一个工作进程在创建后会自动连接到它的主进程。 当 'disconnect' 事件被触发时才会断开连接。


触发disconnect事情的原因有很多,可以是主动调用worker.disconnect(),也可以是工作进程退出或者被kill掉。


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


exit事件会在任何一个工作进程关闭的时候触发。一般用来监测cluster中某一个进程是否异常退出,如果退出的话使用cluster.fork创建新的进程,以保证有足够多的进程来处理请求。


cluster.on('exit', (worker, code, signal) => {
  console.log('工作进程 %d 关闭 (%s). 重启中...',
              worker.process.pid, signal || code);
  cluster.fork();
});


fork事件会在调用cluster.fork方法的时候被触发。


const timeouts = [];
function errorMsg() {
  console.error('连接出错');
}
cluster.on('fork', (worker) => {
  timeouts[worker.id] = setTimeout(errorMsg, 2000);
});


主进程和工作进程的listening事件都会在工作进程调用listen方法的时候触发。


cluster.on('listening', (worker, address) => {
  console.log(
    `工作进程已连接到 ${address.address}:${address.port}`);
});


其中worker代表的是工作线程,而address中包含三个属性:address、 port 和 addressType。 其中addressType有四个可选值:


  • 4 (TCPv4)
  • 6 (TCPv6)
  • -1 (Unix 域 socket)
  • 'udp4' or 'udp6' (UDP v4 或 v6)


message事件会在主进程收到子进程发送的消息时候触发。


当主进程生成工作进程时会触发fork,当工作进程运行时会触发online。


setupMaster方法被调用的时候,会触发setup事件。


cluster中的方法


cluster中三个方法,分别是disconnect,fork和setupMaster。


cluster.disconnect([callback])


调用cluster的disconnect方法,实际上会在cluster中的每个worker中调用disconnect方法。从而断开worker和主进程的连接。


当所有的worker都断开连接之后,会执行callback。


cluster.fork([env])


fork方法,会从主进程中创建新的子进程。其中env是要添加到进程环境变量的键值对。


fork将会返回一个cluster.Worker对象,代表工作进程。


最后一个方法是setupMaster:


cluster.setupMaster([settings])


默认情况下,cluster通过fork方法来创建子进程,但是我们可以通过setupMaster来改变这个行为。通过设置settings变量,我们可以改变后面fork子进程的行为。


我们看一个setupMaster的例子:


const cluster = require('cluster');
cluster.setupMaster({
  exec: 'worker.js',
  args: ['--use', 'https'],
  silent: true
});
cluster.fork(); // https 工作进程
cluster.setupMaster({
  exec: 'worker.js',
  args: ['--use', 'http']
});
cluster.fork(); // http 工作进程


cluster中的属性


通过cluster对象,我们可以通过isMaster和isWorker来判断进程是否主进程。


可以通过worker来获取当前工作进程对象的引用:


const cluster = require('cluster');
if (cluster.isMaster) {
  console.log('这是主进程');
  cluster.fork();
  cluster.fork();
} else if (cluster.isWorker) {
  console.log(`这是工作进程 #${cluster.worker.id}`);
}


可以通过workers来遍历活跃的工作进程对象:


// 遍历所有工作进程。
function eachWorker(callback) {
  for (const id in cluster.workers) {
    callback(cluster.workers[id]);
  }
}
eachWorker((worker) => {
  worker.send('通知所有工作进程');
});


每个worker都有一个id编号,用来定位该worker。


cluster中的worker


worker类中包含了关于工作进程的所有的公共的信息和方法。cluster.fork出来的就是worker对象。


worker的事件和cluster的很类似,支持6个事件:disconnect,error,exit,listening,message和online。


worker中包含3个属性,分别是:id,process和exitedAfterDisconnect。


其中id是worker的唯一标记。


worker中的process,实际上是ChildProcess对象,是通过child_process.fork()来创建出来的。


因为在worker中,process属于全局变量,所以我们可以直接在worker中使用process来进行发送消息。


exitedAfterDisconnect表示如果工作进程由于 .kill() 或 .disconnect() 而退出的话,值就是true。如果是以其他方式退出的话,返回值就是false。如果工作进程尚未退出,则为 undefined。


我们可以通过worker.exitedAfterDisconnect 来区分是主动退出还是被动退出,主进程可以根据这个值决定是否重新生成工作进程。


cluster.on('exit', (worker, code, signal) => {
  if (worker.exitedAfterDisconnect === true) {
    console.log('这是自发退出,无需担心');
  }
});
// 杀死工作进程。
worker.kill();


worker还支持6个方法,分别是:send,kill,destroy,disconnect,isConnected,isDead。


这里我们主要讲解一下send方法来发送消息:


worker.send(message[, sendHandle[, options]][, callback])


可以看到send方法和child_process中的send方法参数其实是很类似的。而本质上,worker.send在主进程中,这会发送消息给特定的工作进程。 相当于 ChildProcess.send()。在工作进程中,这会发送消息给主进程。 相当于 process.send()。


if (cluster.isMaster) {
  const worker = cluster.fork();
  worker.send('你好');
} else if (cluster.isWorker) {
  process.on('message', (msg) => {
    process.send(msg);
  });
}


在上面的例子中,如果是在主进程中,那么可以使用worker.send来发送消息。而在子进程中,则可以使用worker中的全局变量process来发送消息。


总结



使用cluster可以充分使用多核CPU的优势,希望大家在实际的项目中应用起来。

相关文章
|
存储 Web App开发 监控
模拟微信第一篇,nodejs搭建一套高性能分布式的在线文件服务
模拟微信第一篇,nodejs搭建一套高性能分布式的在线文件服务。深度好文实战好文连载:手把手教对象从零开始,开发一款社交通讯APP
451 0
模拟微信第一篇,nodejs搭建一套高性能分布式的在线文件服务
|
6天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
17天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1327 7
|
5天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
301 129
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
4天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。
|
16天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1396 87
|
4天前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
5天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
298 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)