创建具有负载平衡和集群的可扩展 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.rhkb.cn/news/192326.html

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

相关文章

数字媒体技术基础之:常见图片文件格式

在数字图像处理和图形设计领域&#xff0c;了解不同的图片文件格式及其特点是至关重要的。每种格式都有其独特的用途和优势。以下介绍一些最常见的图片文件格式。 JPEG Joint Photographic Experts Group 扩展名&#xff1a;.jpg 或 .jpeg 特点&#xff1a; 1、有损压缩&#x…

navicat导入已有sql表过程

已知我有一个外部的sql表&#xff0c;如图&#xff1a; 想要将其导入navicat并运行。 看一下我的navicat&#xff0c; navicat里已有的数据库并没有library&#xff0c;所以需要建立一个同名的library数据库来存储library.sql文件。 具体步骤如下&#xff1a; 在“本地连接”…

QT windows与linux之间sokcet通信中文乱码问题解决方法

QT windows与linux之间sokcet通信中文乱码问题解决方法 linux发送与接收都转码utf-8: tcpClient ->write( send_msg.toUtf8());//解决乱码&#xff0c;发送转码 接收&#xff1a; QByteArray buffer tcpClient->readAll(); if(!buffer.isEmpty()) { // ui->plain…

C++ VS2015安装教程,下载和安装(下载地址+图解+详细步骤)

说明&#xff1a;VS2015的三个版本分别为&#xff1a; Visual Studio Community(社区版)&#xff1a;满足大部分程序员的需求&#xff08;推荐&#xff09; Visual Studio Professional(专业版) Visual Studio Enterprise(企业版) 1、下载地址(这里只提供Community版) htt…

PlantUML基础使用教程

环境搭建 IDEA插件下载 打开IEDA系列IDE&#xff0c;从FIle–>Settings–>Plugins–>Marketplace 进入到插件下载界面&#xff0c;搜索PlantUML&#xff0c;安装PlantUML Integration和PlantUML Parser两个插件&#xff0c;并重启IDE 安装和配置Graphviz 进入官网…

<MySQL> 查询数据进阶操作 -- 聚合查询

目录 一、聚合查询概述 二、聚合函数查询 2.1 常用函数 2.2 使用函数演示 2.3 聚合函数参数为*或列名的查询区别 2.4 字符串不能参与数学运算 2.5 具有误导性的结果集 三、分组查询 group by 四、分组后条件表达式查询 五、MySQL 中各个关键字的执行顺序 一、聚合查询…

C语言--求一个 3 X 3 的整型矩阵对角线元素之和

一.题目描述 求一个 3 X 3 的整型矩阵对角线元素之和 二.代码实现 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() {int arr[3][3] { 0 };for (int i 0;i < 3;i){for (int j 0;j < 3;j){ printf("请输入数字&#xff1a;");scanf(&…

Webpack Bundle Analyzer包分析器

当我们需要分析打包文件dist里哪些资源可以进一步优化时&#xff0c;就可以使用包分析器插件webpack-bundle-analyzer。NPM上的介绍是使用交互式可缩放树图可视化 webpack 输出文件的大小。 我的是vue2项目。 1、webpack-bundle-analyzer插件的安装 $ npm install --save-dev…

【LittleXi】C程序预处理、编译、汇编、链接步骤

【LittleXi】C程序预处理、编译、汇编、链接步骤 C程序 #include<stdio.h> int main(){int x1,y1;printf("xy%d",xy); }1、预处理 将头文件引入进来、除去注释、宏定义下放 执行指令 g -E esc.c -o esc.i 2、编译 将处理好的代码编译为汇编代码.s 执行…

后端接口性能优化分析-程序结构优化

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&…

加速可编程创新,2023年英特尔FPGA中国技术日披露全矩阵FPGA产品与应用方案

在新场景、新应用海量增长的驱动下&#xff0c;中国本地市场对于FPGA产品的需求也在日益多元化和快速扩展。我们始终致力于以中国客户的实际需求为导向&#xff0c;基于领先的FPGA产品和软件为千行百业提供全场景的解决方案。——叶唯琛 英特尔可编程方案事业部中国总经理 今日…

revit获取FamilySymbol的name

因为想解析把Element的CategoryId跟FamilySymbolId解析并存下来&#xff0c;这样就可以还原Revit中项目浏览器&#xff0c;里面的族的结构层次了。 参考&#xff1a;Revit中“Category、Family、 Familysymbol、 FamilyInstance”之间的关系​​​​​​ 但是对于wall和floor等…

【iOS】将网络请求封装在一个单例类Manager中(AFNetworking、JSONModel)

项目开发中会请求大量不同的API&#xff0c;若将网络请求三板斧直接写在Controller中会代码十分冗杂&#xff0c;干脆直接将AFNetWorking和JSONModel封装到一个全局的Manager单例类中&#xff0c;在Manager类中进行网络请求和数据解析 导入AFNetworking和JSONModel 参考【iOS…

分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测

分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测 目录 分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 Isomap-Adaboost-IHBA-…

CSS特效010:文字颜色渐变的流光效果

查看专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS相关的库、…

竞赛 题目:基于LSTM的预测算法 - 股票预测 天气预测 房价预测

文章目录 0 简介1 基于 Keras 用 LSTM 网络做时间序列预测2 长短记忆网络3 LSTM 网络结构和原理3.1 LSTM核心思想3.2 遗忘门3.3 输入门3.4 输出门 4 基于LSTM的天气预测4.1 数据集4.2 预测示例 5 基于LSTM的股票价格预测5.1 数据集5.2 实现代码 6 lstm 预测航空旅客数目数据集预…

Vatee万腾的数字化掌舵:Vatee科技引领未来的新高度

随着数字化时代的到来&#xff0c;Vatee万腾以其卓越的科技决策力成为引领潮流的掌舵者。 Vatee万腾通过对科技前沿的不懈探索&#xff0c;站在了数字化创新的最前沿。其领先的科技团队致力于发掘并应用最新的数字技术&#xff0c;为用户提供卓越的数字化体验。 Vatee万腾以其…

HTML 之常用标签的介绍

文章目录 h标签p标签a标签img 标签table、tr、td标签ul、ol、li 标签div 标签 h标签 <h> 标签用于定义 HTML 文档中的标题&#xff0c;其中 h 后面跟着一个数字&#xff0c;表示标题的级别。HTML 提供了 <h1> 到 <h6> 六个不同级别的标题&#xff0c;其中 &…

Linux socket编程(3):利用fork实现服务端与多个客户端建立连接

上一节&#xff0c;我们实现了一个客户端/服务端的Socket通信的代码&#xff0c;在这个例子中&#xff0c;客户端连接上服务端后发送一个字符串&#xff0c;而服务端接收到字符串并打印出来后就关闭所有套接字并退出了。 上一节的代码较为简单&#xff0c;在实际的应用中&…

详解 KEIL C51 软件的使用·设置工程·编绎与连接程序

详解 KEIL C51 软件的使用建立工程-CSDN博客 2. 设置工程 (1)在图 2-15 的画面中点击 会弹出如图 2-16 的对话框.其中有 10 个选择页.选择“Target” 项,也就是图 2-16 的画面. 图 2-16 在图 2-16 中,箭头所指的是晶振的频率值,默认是所选单片机最高的可用频率值.该设置值与单…