
是一种服务器端 ,使用事件驱动、无阻塞输入输出(I/O)模型。它在构建快速、可扩展的 *** 应用程序方面广受认可。它还拥有一个庞大的社区和丰富的模块库,可简化各种任务和流程。
集群可使 在多个进程上运行,从而提高其性能。这种技术可让应用程序充分发挥多核系统的潜力。
本文将全面介绍 Node.js 中的集群及其对应用程序性能的影响。
默认情况下,Node.js 应用程序在单线程上运行。这种单线程特性意味着 Node.js 无法使用多核系统中的所有内核,而目前大多数系统都是如此。
通过利用非阻塞 I/O 操作和异步编程技术,Node.js 仍然可以同时处理多个请求。
但是,繁重的计算任务会阻塞事件循环,导致应用程序无响应。因此,Node.js 提供了一个本地集群模块(无论其单线程性质如何),以充分利用多核系统的总处理能力。
运行多个进程可充分利用多个中央处理器(CPU)内核的处理能力,从而实现并行处理、缩短响应时间并提高吞吐量。这反过来又提高了 Node.js 应用程序的性能和可扩展性。
允许 Node.js 应用程序创建一个由并发运行的子进程组成的群集,每个子进程处理应用程序的部分工作负载。
在初始化集群模块时,应用程序会创建主进程,然后将子进程分叉为工作进程。主进程充当负载平衡器,将工作负载分配给工作进程,同时每个工作进程监听传入的请求。
Node.js 群集模块有两种分配传入连接的 *** 。
从理论上讲,第二种 *** 更为复杂,应该能提供更好的性能。但实际上,连接的分布非常不平衡。中提到,所有连接的 70% 都在八个进程中的两个进程中结束。
现在,让我们来看看集群在 Node.js 应用程序中的效果。本教程使用一个 Express 应用程序,该程序有意运行一项繁重的计算任务,以阻塞事件循环。
首先,在不使用集群的情况下运行此应用程序。然后,使用基准测试工具记录性能。然后,在应用程序中实施聚类,并重复进行基准测试。最后,比较结果,看看聚类如何提高应用程序的性能。
要理解本教程,您必须熟悉 Node.js 和 。设置您的 :
mkdir cluster-tutorial
cd cluster-tutorial && touch no-cluster.js && touch cluster.js
npm init -y
npm install express
在 no-cluster.js 文件中,添加以下代码块:
const express = require("express");
const PORT = 3000;
const app = express();
app.get("/", (req, res) => {
res.send("Response from server");
});
app.get("/slow", (req, res) => {
//Start timer
console.time("slow");
// Generate a large array of random numbers
let arr = [];
for (let i = 0; i < 100000; i++) {
arr.push(Math.random());
}
// Perform a heavy computation on the array
let sum = 0;
for (let i = 0; i {
console.log(`Server listening on port ${PORT}`);
});
上面的代码块创建了一个在 3000 端口运行的 express 服务器。服务器有两个路由,一个是根( / )路由,另一个是 /slow 路由。根路由会向客户端发送一条响应信息: “来自服务器的响应”。
不过, /slow 路由会故意进行一些繁重的计算,以阻断事件循环。该路由启动一个计时器,然后使用 for 循环将 100,000 个随机数填入一个数组。
然后,使用另一个 for 循环,对生成数组中的每个数字进行平移并相加。完成后定时器结束,服务器响应结果。
运行下面的命令启动服务器:
node no-cluster.js
然后向 localhost:3000/slow 发起 GET 请求。
在此期间,如果您尝试向服务器发出任何其他请求(例如向根路由 ( / ) 发出请求),响应速度都会很慢,因为 /slow 路由阻塞了事件循环。
使用集群模块生成子进程,以确保您的应用程序在执行繁重的计算任务时不会出现无响应和阻塞后续请求的情况。
每个子进程运行其事件循环,并与父进程共享服务器端口,从而更好地利用可用资源。
首先,在 cluster.js 文件中导入 Node.js 集群和 os 模块。集群模块允许创建子进程,以便在多个 CPU 内核之间分配工作量。
os 模块提供有关计算机操作系统的信息。您需要使用该模块来获取系统上可用的内核数量,确保创建的子进程数量不会超过系统内核数量。
注:创建的子进程数量超过系统内核数量会导致系统在进程间切换花费更多时间。这会增加开销并降低性能。
添加下面的代码块,导入这些模块并获取系统内核的数量:
const cluster = require("node:cluster");
const numCores = require("node:os").cpus().length;
接下来,将下面的代码块添加到 cluster.js 文件中:
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
console.log(`This machine has ${numCores} cores`);
// Fork workers.
for (let i = 0; i {
console.log(`worker ${worker.process.pid} died`);
// Replace the dead worker
console.log("Starting a new worker");
cluster.fork();
});
}
上面的代码块会检查当前进程是主进程还是工作进程。如果为真,代码块将根据系统内核数生成子进程。接下来,它会监听进程的退出事件,并通过生成新进程来替换它们。
最后,用 else 代码块封装所有相关的表达逻辑。完成后的 cluster.js 文件应与下面的代码块相似。
//cluster.js
const express = require("express");
const PORT = 3000;
const cluster = require("node:cluster");
const numCores = require("node:os").cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
console.log(`This machine has ${numCores} cores`);
// Fork workers.
for (let i = 0; i {
console.log(`worker ${worker.process.pid} died`);
// Replace the dead worker
console.log("Starting a new worker");
cluster.fork();
});
} else {
const app = express();
app.get("/", (req, res) => {
res.send("Response from server");
});
app.get("/slow", (req, res) => {
console.time("slow");
// Generate a large array of random numbers
let arr = [];
for (let i = 0; i < 100000; i++) {
arr.push(Math.random());
}
// Perform a heavy computation on the array
let sum = 0;
for (let i = 0; i {
console.log(`Server listening on port ${PORT}`);
});
}
实施集群后,多个进程将处理请求。这意味着,即使在计算任务繁重的情况下,您的应用程序也能保持响应速度。
要在 Node.js 应用程序中准确演示和显示集群的效果,请使用 npm 软件包 比较集群前后应用程序的性能。
运行以下命令全局安装 loadtest:
npm install -g loadtest
loadtest 软件包会在指定的 HTTP/WebSockets URL 上运行负载测试。
接下来,在终端实例中启动 no-cluster.js 文件。然后,打开另一个终端实例,运行下面的负载测试:
loadtest http://localhost:3000/slow -n 100 -c 10
上面的命令向未集群的应用程序发送了 100 个并发量为 10 的请求。运行该命令会产生以下结果:

非群集应用程序负载测试结果。
根据结果,在没有群集的情况下,完成所有请求大约需要 100 秒,最长的请求需要 12 秒才能完成。
测试结果因系统而异。
接下来,停止运行 no-cluster.js 文件,在终端实例上启动 cluster.js 文件。然后,打开另一个终端实例并运行此负载测试:
loadtest http://localhost:3000/slow -n 100 -c 10
上述命令将向集群应用程序发送 100 个并发量为 10 的请求。
运行该命令会产生以下结果:

集群应用程序负载测试结果。
使用集群后,请求只需 0.13 秒(136 毫秒)即可完成,比未集群的应用程序需要 100 秒的时间大大缩短。此外,集群应用程序上最长的请求完成时间为 41 毫秒。
这些结果表明,实施集群可以显著提高应用程序的性能。请注意,您应该使用 等流程管理软件来管理生产环境中的集群。
Node.js 中的集群可以创建多个工作进程来分配工作负载,从而提高 Node.js 应用程序的性能和可扩展性。正确实施集群对于充分发挥这项技术的潜力至关重要。
在 Node.js 中实施集群时,设计架构、管理资源分配和尽量减少 *** 延迟都是至关重要的因素。这种实现方式的重要性和复杂性正是 PM2 等进程管理器应在生产环境中使用的原因。
您如何看待 Node.js 集群?您以前使用过吗?请在评论区分享!
宝塔面板现在已经成为国内许多站长必备的服务器管理必备工具。相比直接使用SSH+FTP来管理服务器,宝塔面板可以提供可视化管理,包括文件管理、数据库管理、数据备份、SSL配置等等。 如果你希望更简单高效地管理您的网站及服务器,宝塔面板是不错的选择。下面是一些宝塔面板安装及常见问题:...
宝塔面板其中一个最为便捷的功能之一,无需SFTP或者FTP即可对服务器的文件内容进行上传、下载、编辑及删除等管理操作。 文件管理,用于管理该服务器上的文件内容。 文件的基础操作 文件的基础操作有哪些了,主要有这些方面:复制、粘贴、剪切、删除、重命名、压缩、刷新、新建文件、新建目录。...
宝塔面板的计划任务,主要用于安排和管理需要定时执行的任务,如备份、内存清理等。其实对于大部分站长来说,主要使用该板块的备份网站、备份数据库及释放内存的三个定时任务计划。 Shell脚本的添加 输入任务名称,选择执行周期,输入执行的脚本内容。 注意事项: 输入脚本内容...
经过几个小时的努力工作后,您是否感到眼睛疲劳或难以阅读代码?许多程序员在开始头疼之前从没想过要切换字体。 如果您经常发现在尝试扫描一千行代码时眼睛模糊不清,或者在停止编码数小时后头疼,那么可能是时候尝试一种新字体了。即使您没有遇到这些症状,设计良好的字体通常也比默认系统字体具有更好的可读性。...
想成为一名网络开发人员或好奇工作的哪些子类型的薪水最高?Web开发是一个竞争激烈、多样化的行业,随着新语言和框架的出现而不断发展。 询问Web开发人员的薪水是一个难以解决的问题(尽管我们尝试)。有太多的因素需要考虑。 无论您是自由开发者还是有兴趣从事更传统的工作、喜欢前端或后端工作,或者想知...
PHP开发:有些人认为它是,另一些人认为它是一种过时的技术,不值得花时间学习。但是这些数字说明了什么,尤其是当您查看PHP开发人员的薪水时? 虽然肯定有许多更新、更炫、更令人兴奋的语言,但PHP仍然是后端Web开发的可靠主食,也是许多雇主仍在寻找的技能。 有兴趣自己成为PHP开发人员吗?我们...