10行代码让Nodejs处理请求的能力提升5x倍

2023-10-08 23:50

本文主要是介绍10行代码让Nodejs处理请求的能力提升5x倍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

image.png

Node.js以单线程、非阻塞性能工作,在CPU中作为单个进程工作。无论使用多么强大的服务器和资源,单线程进程所能做的都是有限的。

Node.js被设计用于构建具有多个节点的分布式应用程序,因此得名Node.js。

工作负载是我们开始扩展应用程序的主要原因之一,包括可用性和容错性。我们可通过多种方式进行扩展,其中最简单的解决方案之一是克隆。我们可以使用Node.js提供的Cluster Module进行克隆。

在开始使用资源利用率Node.Js服务器处理请求之前,让我们了解一下Cluster模块的基本工作原理。

Cluster模块如何工作?

集群模块有两种类型的进程,Master和Worker。所有传入的请求都由主进程处理,主进程决定由哪个Worker处理传入的请求。Worker进程可以被认为是普通的Node.Js单实例服务器,它服务于请求。

主进程如何分配请求的连接?

  1. 第一种方法(除了Windows以外的所有平台上的默认方法)是轮询方法,其中主进程在一个端口上监听,接受新连接,并以轮询方式将它们分发给各个工作进程,并使用一些内置的负载判断来避免工作进程超载。

image.png

  1. 第二种方法是主进程创建侦听套接字并将其发送给感兴趣的工作程序。然后,工作进程直接接受传入的连接请求。

从理论上讲,第二种方法性能最好。然而,在实践中,由于操作系统调度程序的变幻莫测,分布往往非常不平衡。我们观察到超过70%的连接只在两个进程中结束,而这两个进程总共有8个。

创建一个简单的Node.js服务器

让我们创建最简单的Node.js服务器:

/*** server.js ***/
const http = require(“http”);
// get the process ID of Node Server
const processId = process.pid;
// Creating server and handling request
const server = http.createServer((req, res) => {// Simulate CPU Workfor (let index = 0; index < 1e7; index++);res.end(`Process handled by pid: ${processId}`);
});
// start server and listen the request
server.listen(8080, () => {console.log(`Server Started in process ${processId}`);
});

服务器反馈出以下响应结果:

image.png

对改服务器进行负载测试,这里我们使用ApacheBench Tool

我们将在10秒内用500个并发请求访问Node.js服务器。

➜ test_app ab -c 500 -t 10 http://localhost:8080/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking localhost (be patient)
Finished 3502 requestsServer Software:
Server Hostname: localhost
Server Port: 8080Document Path: /
Document Length: 29 bytesConcurrency Level: 500
Time taken for tests: 11.342 seconds
Complete requests: 3502
Failed requests: 0
Total transferred: 416104 bytes
HTML transferred: 116029 bytes
Requests per second: 308.76 [#/sec] (mean)
Time per request: 1619.385 [ms] (mean)
Time per request: 3.239 [ms] (mean, across all concurrent requests)
Transfer rate: 35.83 [Kbytes/sec] receivedConnection Times (ms)
min mean[+/-sd] median max
Connect: 0 6 3.7 5 17
Processing: 21 1411 193.9 1412 2750
Waiting: 4 742 395.9 746 1424
Total: 21 1417 192.9 1420 2750Percentage of the requests served within a certain time (ms)
50% 1420
66% 1422
75% 1438
80% 1438
90% 1624
95% 1624
98% 1624
99% 1625
100% 2750 (longest request)

这个简单服务器,在500个并发请求的水平上,总共服务了3502个请求。每秒308个请求,每次请求的时间为1619毫秒。

处理的请求数量很好,它应该适用于大多数中小型应用程序。但是我们没有充分利用资源,而且大多数可用资源都处于闲置状态。

使用 Cluster 模块

现在我们来尝试一下

/** cluster.js **/
const os = require(“os”);
const cluster = require(“cluster”);
if (cluster.isMaster) {const number_of_cpus = os.cpus().length;console.log(`Master ${process.pid} is running`);console.log(`Forking Server for ${number_of_cpus} CPUs\n`);// Create a Worker Process for each Available CPUfor (let index = 0; index < number_of_cpus; index++) {cluster.fork();}// When Worker process has died, Log the workercluster.on(“exit”, (worker, code, signal) => {console.log(`\nWorker ${worker.process.pid} died\n`);});
} else {// if Worker process, master is false, cluster.isWorker is true// worker starts server for individual cpus// the worker created above is starting server require(./server”);
}

我的个人电脑是i7第8代有8个处理器核。考虑到现在大多数可用的cp最低配置也是双核,因此剩下的7个核的资源都处于空闲状态*。

现在,让我们运行创建的cluster.js文件,服务器给我们的响应如下:

image.png

如果您实现了上述集群,那么您将充分利用您的CPU/服务器性能。请求由同一个主进程接收,但是会根据操作系统的调度分配给任一的工作进程处理。

对集群进行负载测试

➜  test_app ab -c 500 -t 10  http://localhost:8080/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Finished 20374 requestsServer Software:
Server Hostname:        localhost
Server Port:            8080Document Path:          /
Document Length:        29 bytesConcurrency Level:      500
Time taken for tests:   10.000 seconds
Complete requests:      20374
Failed requests:        0
Total transferred:      2118896 bytes
HTML transferred:       590846 bytes
Requests per second:    2037.39 [#/sec] (mean)
Time per request:       245.412 [ms] (mean)
Time per request:       0.491 [ms] (mean, across all concurrent requests)
Transfer rate:          206.92 [Kbytes/sec] receivedConnection Times (ms)
min  mean[+/-sd] median   max
Connect:        0    0   1.3      0      12
Processing:     6  242  15.6    241     369
Waiting:        6  242  15.5    241     368
Total:         18  242  15.5    241     371Percentage of the requests served within a certain time (ms)
50%    241
66%    244
75%    246
80%    247
90%    251
95%    259
98%    283
99%    290
100%    371 (longest request)

上面简单的Node.js服务器在我们的负载测试中每秒处理308个请求,现在这个数字已经增加到2037个,处理的请求数量增加了6倍。此外,以前的每请求时间是1619毫秒,现在已经减少到245ms。我们之前总共提供3502个请求,现在已经增加到20374个请求(增加了5.8倍)。如果你看看上面的实现,这个巨大的改进是由10行代码引起的。我们也不需要重构现有的服务器代码,是不是很香。

可用性和零停机时间

_

对我们目前所取得的进展感到兴奋,现在它变得更好了。

但是当我们有一个服务器实例,而该服务器崩溃时。服务器必须重新启动,这样会有停机时间。即使流程是自动化的,也会有延迟,在此期间不能服务任何请求。

模拟服务器崩溃:

*** server.js ***/
const http = require(“http”);
// get the process ID of Node Server
const processId = process.pid;
// Creating server and handling request
const server = http.createServer((req, res) => {// Simulate CPU Workfor (let index = 0; index < 1e7; index++);res.end(`Process handled by pid: ${processId}`);
});
// start server and listen the request
server.listen(8080, () => {console.log(`Server Started in process ${processId}`);
});
// Warning: Only For Testing and Visualization Purpose
// Don't add the code below in production
// Let's simulate Server Randomly Crashing using process.exit()
setTimeout(() => {process.exit(1);
}, Math.random() * 10000);

现在,出于模拟目的,如果我们将上面高亮显示的代码添加到服务器代码中。然后启动我们的服务器,我们可以看到一个接一个的所有服务器都崩溃了。由于没有可用的Worker,主进程也可能崩溃。这种崩溃在现实情况很常见。

现在,请记住,这是由Cluster Module创建的8个服务器的情况。当我们有一个服务器实例并且在它崩溃时,在此期间没有请求可以被服务。

➜  test_app node cluster.js
Master 63104 is running
Forking Server for 8 CPUs
Server Started in process 63111
Server Started in process 63118
Server Started in process 63112
Server Started in process 63130
Server Started in process 63119
Server Started in process 63137
Server Started in process 63142
Server Started in process 63146
Worker 63142 died
Worker 63112 died
Worker 63111 died
Worker 63146 died
Worker 63119 died
Worker 63130 died
Worker 63118 died
Worker 63137 died
➜  test_app

处理零停机时间

当我们有一个服务器的多个实例时,服务器的可用性可以很容易地提高。
让我们打开cluster.js文件,并将突出显示的代码添加到cluster.js:

/** cluster.js **/
const os = require(“os”);
const cluster = require(“cluster”);
if (cluster.isMaster) {const number_of_cpus = os.cpus().length;console.log(`Master ${process.pid} is running`);console.log(`Forking Server for ${number_of_cpus} CPUs\n`);// Create a Worker Process for each Available CPUfor (let index = 0; index < number_of_cpus; index++) {cluster.fork();}// When Worker process has died, Log the workercluster.on(“exit”, (worker, code, signal) => {/*** The condition checks if worker actually crashed and* wasn't manually disconnected or killed by master process.** The condition can be changed by desired error code,* and condition.*/if (code !== 0 && !worker.exitedAfterDisconnect) {console.log(`Worker ${worker.process.pid} died`);cluster.fork();}});
} else {// if Worker process, master is false, cluster.isWorker is true// worker starts server for individual cpus// the worker created above is starting serverrequire(./server”);
}

实现服务器重启的负载测试:

运行实现了集群切换的服务器(运行:node cluster.js)。现在,让我们打开基准测试工具,开始对服务器进行基准测试。

➜  test_app ab -c 500 -t 10 -r http://localhost:8080/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Finished 20200 requests
Server Software:        
Server Hostname:        localhost
Server Port:            8080
Document Path:          /
Document Length:        29 bytes
Concurrency Level:      500
Time taken for tests:   10.000 seconds
Complete requests:      20200
Failed requests:        12(Connect: 0, Receive: 4, Length: 4, Exceptions: 4)
Total transferred:      2100488 bytes
HTML transferred:       585713 bytes
Requests per second:    2019.91 [#/sec] (mean)
Time per request:       247.536 [ms] (mean)
Time per request:       0.495 [ms] (mean, across all concurrent requests)
Transfer rate:          205.12 [Kbytes/sec] received
Connection Times (ms)min  mean[+/-sd] median   max
Connect:        0    0   1.5      0      13
Processing:    13  243  15.7    241     364
Waiting:        0  243  16.0    241     363
Total:         22  243  15.5    241     370
Percentage of the requests served within a certain time (ms)50%    24166%    24575%    24880%    25090%    25895%    26598%    27399%    287100%    370 (longest request)
➜  test_app

在上面的负载测试中,在500并发请求和2019请求每秒的水平上。总共有20200个请求,只有12个请求失败,这意味着我们的服务器有99.941%的正常运行时间,即使服务器一个接一个地崩溃并重新启动。

考虑到我们只增加了3行额外的代码,这真是太棒了!

更多精彩关注公众号【程序员石磊】

这篇关于10行代码让Nodejs处理请求的能力提升5x倍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/168835

相关文章

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

安装nodejs环境

本文介绍了如何通过nvm(NodeVersionManager)安装和管理Node.js及npm的不同版本,包括下载安装脚本、检查版本并安装特定版本的方法。 1、安装nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash 2、查看nvm版本 nvm --version 3、安装

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

D4代码AC集

贪心问题解决的步骤: (局部贪心能导致全局贪心)    1.确定贪心策略    2.验证贪心策略是否正确 排队接水 #include<bits/stdc++.h>using namespace std;int main(){int w,n,a[32000];cin>>w>>n;for(int i=1;i<=n;i++){cin>>a[i];}sort(a+1,a+n+1);int i=1