创建具有负载平衡和集群的可扩展 Node.js 应用程序

创建具有负载平衡和集群的可扩展 Node.js 应用程序

负载平衡是提高应用程序性能、可扩展性和可用性的一项重要技术。当客户端向负载均衡器发出请求时,负载均衡器根据预定义的规则将请求分发到不同的实例。

可以使用cluster集群模块或 PM2 等工具根据负载均衡器的流量动态创建和删除实例。集群模块可用于创建工作进程,而PM2可用于进程管理、负载均衡、零停机部署、日志管理、进程集群和安全。

PM2Node.js 应用程序的流行流程管理器,提供了一系列有用的功能和优点,包括负载平衡和流程集群。为了使用 PM2 实现负载均衡,我们可以创建一个 Node.js 集群。Node.js 处理传入流量并将其分配给可用的工作进程。工作进程的最佳数量取决于应用程序的具体需求,并且应仔细优化性能和可扩展性。

在这里插入图片描述

负载均衡

首先,我们来讨论一下负载均衡的基本概念。负载均衡是一种在多个服务器之间分配传入网络流量的工具,以确保没有任何一台服务器因请求而不堪重负。负载均衡器可以使用硬件设备或软件程序来实现,它们通常使用算法来确定如何分配流量。

对于 Node.js,负载均衡可以在不同服务器上运行的多个 Node.js 实例之间分发传入的 HTTP 请求。这可以确保没有单个实例因请求而过载,从而提高性能和可靠性。

当客户端向负载均衡器发出请求时,负载均衡使用算法来确定哪个 Node.js 实例应处理该请求。可以使用多种不同的算法,包括:

  • 循环:此算法只是按顺序循环可用的 Node.js 实例,将每个新请求发送到序列中的下一个实例。
  • 最少连接:此算法选择收到请求时活动连接最少的 Node.js 实例。
  • IP 哈希:此算法计算客户端 IP 地址的哈希,并使用该值来确定哪个 Node.js 实例应处理该请求。这可以帮助确保来自同一客户端的请求始终发送到同一实例。

还有其他算法,例如随机、加权循环、加权最少连接、粘性会话,但这不在本文的讨论范围内。

一旦负载均衡确定哪个 Node.js 实例应处理该请求,它就会将该请求发送到该实例。如果实例已经运行并且可用,它将立即处理请求。但是,如果没有可用实例,负载均衡可以动态创建新实例来处理请求。

动态创建Node实例

动态创建新 Node.js 实例的一种方法是使用child_process工作进程模块。工作进程只是 Node.js 运行时的一个单独实例,可用于处理请求。要创建新的工作进程,可以使用child_process模块,如下所示:

const { fork } = require('child_process');// 创建一个新的工作进程
const worker = fork('./worker.js');// 监听来自工作进程的消息
worker.on('message', (msg) => {console.log(`Received message from worker: ${msg}`);
});// 向工作进程发送消息
worker.send('Hello from the main process!');

在此示例中,我们使用child_process模块中的fork方法从名为worker的单独 Node.js 文件创建一个新的工作进程。然后,我们使用on('message')方法侦听来自工作进程的消息,每当工作进程将消息发送回主进程时就会调用该方法。我们还使用send()方法向工作进程发送消息,该方法将消息从主进程发送到工作进程。

以下是worker.js文件的示例:

// 监听来自主进程的消息
process.on('message', (msg) => {console.log(`Received message from main process: ${msg}`);// 向主进程发送消息process.send('Hello from the worker process!');
});

使用child_process实现负载均衡

以下是在 Node.js 中使用工作进程的实现负载均衡的示例:

const http = require('http');
const { fork } = require('child_process');
const url = require('url');// 创建工作进程数组
const workers = [];for (let i = 0; i < 4; i++) {workers.push(fork('./server.js'));
}// 创建一个循环计数器
let counter = 0;// 创建负载均衡
http.createServer((req, res) => {// 根据循环计数器获取下一个工作进程const worker = workers[counter];// 增加循环计数器counter = (counter + 1) % workers.length;// 发送到工作进程const parsedUrl = url.parse(req.url, true);worker.send({ path: parsedUrl.pathname });// 监听worker.on('message', (message) => {res.writeHead(200);res.end(message);});
}).listen(8000);console.log('server running on port 8000');

在此代码中,我们首先通过fork创建server.js工作进程4次,并放入到数组。这将创建四个独立的 Node.js 运行时实例,每个实例运行自己的server.js代码副本。

server.js文件:

const http = require('http');
const https = require('https');// 创建http服务
http.createServer((req, res) => {res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });res.end();
}).listen(80);// 创建https服务
https.createServer(options, (req, res) => {// ...
}).listen(443);

然后,我们创建一个循环计数器变量,用于跟踪将每个传入请求发送到哪个工作进程。我们最初将计数器设置为零。

接下来,我们创建一个侦听端口 80HTTP 服务器。对于每个传入请求,我们根据循环计数器从工作程序数组中获取下一个工作进程。然后我们增加计数器以准备下一个请求。

我们使用send方法将传入请求发送到选定的工作进程。工作进程接收请求并使用process.send方法发回响应。我们设置一个消息监听器来接收来自worker.js的响应,并使用它来将响应发送回客户端。

在工作进程中,我们有以下代码:

const http = require('http');// 以当前进程的ID创建一个 HTTP 服务器
http.createServer((req, res) => {res.writeHead(200);res.end(`Hello from worker ${process.pid}\n`);
}).listen(0, () => {console.log(`Worker ${process.pid} listening on port ${server.address().port}`);
});// 设置消息侦听器以接收来自负载均衡的请求
process.on('message', (message) => {const server = http.createServer((req, res) => {res.writeHead(200);res.end(`Hello from worker ${process.pid}\n`);});server.listen(() => {process.send(`http://localhost:${server.address().port}${message.path}`);});
});

在此代码中,我们创建一个 HTTP 服务器,该服务器在收到请求时以当前进程 ID 进行响应。我们还设置了一个消息侦听器来接收来自负载均衡的传入请求。

当工作进程收到来自负载均衡器的消息时,它会创建一个新的 HTTP 服务器来侦听随机端口。然后,它将一条消息发送回负载均衡器,其中包含新服务器的 URL(包括请求的路径)。

负载均衡接收来自工作线程的响应并将其发送回客户端。客户端看到来自负载均衡的响应,就好像它直接来自工作进程一样,即使它实际上是由负载均衡转发的。

这是一个非常简单的负载均衡示例,它使用工作进程在多个 Node.js 实例之间分发传入请求。然而,这种实现有一些限制。例如,如果工作进程崩溃或变得无响应,负载均衡将继续向该工作进程发送请求,这可能会导致性能不佳或停机。

为了克服这个问题,我们可以使用更先进的负载均衡技术,例如健康检查或动态扩展。运行状况检查可用于监视工作进程的运行状况并从池中删除无响应的进程。动态扩展可用于根据流量模式或资源使用情况自动添加或删除工作进程。

除了work_process之外,Node.js 还具有一个内置cluster模块,可用于创建 Node.js 实例集群。cluster模块与工作进程类似,但它提供了更高级的功能,例如自动负载平衡和进程管理。

使用cluster实现负载均衡

以下是使用cluster模块在 Node.js 中创建负载均衡的示例:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;if (cluster.isMaster) {console.log(`Master ${process.pid} is running`);for (let i = 0; i < numCPUs; i++) {cluster.fork();}cluster.on('exit', (worker, code, signal) => {console.log(`Worker ${worker.process.pid} died`);cluster.fork();});
} else {http.createServer((req, res) => {res.writeHead(200);res.end('hello world\n');}).listen(8000);console.log(`Worker ${process.pid} started`);
}

在此示例中,我们使用cluster模块创建 Node.js 实例集群。isMaster属性检查当前进程是否为主进程,如果是,则代码使用cluster.fork()方法为每个可用 CPU 核心创建一个工作进程。

该代码还为exit事件设置了一个事件侦听器,该事件侦听器在工作进程终止时发出。当工作进程死亡时,事件侦听器会记录一条消息并派生一个新的工作进程来替换已死亡的工作进程。

如果当前进程不是主进程(即它是工作进程),则代码会设置一个 HTTP 服务器,该服务器侦听端口 8000 并使用“hello world”消息响应请求。

使用 PM2 进行负载平衡

PM2Process Manager 2 )是 Node.js 应用程序的流行流程管理器,它提供了一系列用于管理和扩展 Node.js 应用程序的有用功能。PM2 可用于流程监控、负载平衡、零停机部署、日志管理、流程集群和安全。

PM2 的主要功能之一是它能够为 Node.js 应用程序执行负载平衡。PM2 可用于跨多个 Node.js 进程分配传入流量,这有助于提高应用程序性能和可扩展性。PM2 还可以创建 Node.js 进程集群,这有​​助于利用多个 CPU 核心并提高应用程序性能和吞吐量。

以下是如何在 Node.js 应用程序中使用 PM2 进行负载平衡的示例:

const http = require('http');const server = http.createServer((req, res) => {res.writeHead(200);res.end(`Hello from process ${process.pid}\n`);
});// 使用pm2
const cluster = require('pm2').clusterMode();if (cluster.isMaster) {console.log(`Master ${process.pid} is running`);for (let i = 0; i < 4; i++) {cluster.fork();}
} else {server.listen(8000);console.log(`Worker ${process.pid} started`);
}

在此示例中,我们使用 Node.js中的http模块创建一个简单的 HTTP 服务器。然后,我们通过调用启用进程集群和负载平衡来使用 PM2 启动服务器。

如果当前进程是主进程,我们使用cluster.fork()来启动四个工作进程。每个工作进程将处理来自客户端的传入 HTTP 请求。如果当前进程是工作进程,我们通过调用启动 HTTP 服务器并记录一条消息以表明工作进程已启动。

当客户端向服务器发出请求时,PM2 将在可用的工作进程之间分配请求,这有助于提高应用程序性能和可扩展性。通过使用 PM2 进行负载平衡,我们可以确保 Node.js 应用程序能够处理高水平的流量并提供可靠且响应迅速的用户体验。

注意:在提供的示例代码中fork四个工作进程的决定是任意的,给定应用程序的最佳工作进程数量取决于可用 CPU 核心、应用程序大小和预期级别等因素的流量。
一般来说,建议每个 CPU 核心有一个工作进程,以最大限度地提高性能和可扩展性。但是,工作进程的最佳数量可能会根据应用程序的具体需求而有所不同。

如果我们的负载均衡过载,我们可以通过添加更多资源(例如额外的服务器或 CPU)来解决问题,或者通过优化代码或配置来减少服务器上的负载。我们还可以使用先进的负载均衡技术,例如动态扩展或自动扩展,根据流量模式自动调整 Node.js 实例的数量。

总结

负载平衡是提高 Node.js 应用程序性能和可靠性的一项重要技术。负载均衡器使用算法将传入流量分配到在多个服务器上运行的不同 Node.js 实例,并且可以使用work_process或者cluster模块等技术根据流量模式动态创建和删除 Node.js 实例。了解 Node.js 中的进程、子进程和进程生成对于构建可扩展且高效的 Node.js 应用程序也很重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/175441.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用vue2实现todolist待办事项

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

Java版B/S架构云his医院信息管理系统源码(springboot框架)

一、技术框架 ♦ 前端&#xff1a;AngularNginx ♦ 后台&#xff1a;JavaSpring&#xff0c;SpringBoot&#xff0c;SpringMVC&#xff0c;SpringSecurity&#xff0c;MyBatisPlus&#xff0c;等 ♦ 数据库&#xff1a;MySQL MyCat ♦ 缓存&#xff1a;RedisJ2Cache ♦ 消息队…

Android设计模式--工厂模式

一&#xff0c;定义 工厂模式与Android 设计模式--单例模式-CSDN博客&#xff0c;Android设计模式--Builder建造者模式-CSDN博客&#xff0c;Android设计模式--原型模式-CSDN博客 一样&#xff0c;都是创建型设计模式。 工厂模式就是定义一个用于创建对象的接口&#xff0c;让…

pycharm pro v2023.2.4(Python编辑开发)

PyCharm2023是一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;专门为Python编程语言设计。以下是PyCharm2023的一些主要功能和特点&#xff1a; 代码编辑器&#xff1a;PyCharm2023提供了一个功能强大的代码编辑器&#xff0c;支持语法高亮、自动补全、代码调试、版…

【移远QuecPython】EC800M物联网开发板的MQTT协议腾讯云数据上报

【移远QuecPython】EC800M物联网开发板的MQTT协议腾讯云数据上报 文章目录 导入库初始化设置MQTT注册回调订阅发布功能开启服务发送消息函数打包调用测试效果附录&#xff1a;列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 导入库 from TenCentYun import TX…

无标题栏的Qt子窗体在父窗体中停靠时,如何做到严丝合缝

目录 1. 问题的提出 2. 一般实现 3. 加强版 1. 问题的提出 由于业务的要求&#xff0c;需要从父窗体弹出一个子窗体&#xff0c;该子窗体无标题栏&#xff0c;且该子窗体要停靠到父窗体右下角。这个看似很容易的问题&#xff0c;细研起来其实不容易&#xff01; 2. 一般实现…

VScode+python开发,多个解释器切换问题

内容&#xff1a;主要VScode使用多个解释器 环境准备 VScode编辑器&#xff0c;两个版本python解释器 python3.7.2 python3.11.6 问题&#xff1a; 目前我们的电脑安装了python3.7.2、python3.11.6两个解释器&#xff0c;在vscode编辑器中&#xff0c;无法切换解释器使用如…

​软考-高级-系统架构设计师教程(清华第2版)【第6章 数据库设计基础知识(234~262)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第6章 数据库设计基础知识&#xff08;234~262&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

简单实现,在nodejs中简单使用kafka

什么是 Kafka Kafka 是由 Linkedin 公司开发的&#xff0c;它是一个分布式的&#xff0c;支持多分区、多副本&#xff0c;基于 Zookeeper 的分布式消息流平台&#xff0c;它同时也是一款开源的基于发布订阅模式的消息引擎系统。 Kafka 的基本术语 消息&#xff1a;Kafka 中的…

Django 的国际化与本地化详解

概要 随着全球化的发展&#xff0c;为 Web 应用提供多语言支持变得日益重要。Django 作为一个功能强大的 Web 框架&#xff0c;提供了一套完整的国际化&#xff08;i18n&#xff09;和本地化&#xff08;l10n&#xff09;工具&#xff0c;使得开发多语言应用变得简单。本文将详…

【软考篇】中级软件设计师 第一部分

中级软件设计师 第一部分 一. 计算机硬件1.1 运算器1.2 控制器 二. 数据的进制2.1 数的表示2.2 数的编码方式2.2.1 数据运算用补码运算 2.3 码制的取值范围2.3.1 例题一 三. 浮点的表示3.1 浮点数运算 四. 运算符五. 校验码5.1 海明校验码 六. 计算机指令6.1 计算机体系结构分类…

Android Matrix的使用详解(通过矩阵获取到图片缩放比例和角度)

网上查了好久相关的资料&#xff0c;都没有明确的答案。最终通过多次测试结果&#xff0c;结合安卓定义的矩阵含义&#xff0c;推算出来矩阵的数学含义以及相关的计算公式 1.获取Matrix矩阵&#xff1a; Matrix matrix new Matrix(); float[] matrixValues new float[9]; …