node.js는 클러스터를 사용하여 multi-process_node.js를 구현합니다.
먼저 다음과 같이 엄숙히 선언합니다.
nodeJS는 비동기식 언어입니다!
nodeJS는 비동기식 언어입니다!
nodeJS는 비동기식 언어입니다!
중요한 말은 3번 말하세요. nodeJS는 자체적인 장점을 가지고 태어났기 때문에 탄생 이후 수천 명의 팬이 찾았습니다(나도 NodeJS의 열렬한 팬입니다). 그러나 그 멍청한 PHP는 실제로 내 NodeJS 성능을 비웃었습니다. 불안정하고 신뢰할 수 없으며 단일 코어 CPU만 사용할 수 있다고 합니다. 핫치킨 노드JS
젠장!
하지만 형은 형이고 nodeJS는 이미 v0.8에 클러스터 모듈을 추가했습니다. PHP를 완전히 뺨 때리지만, PHP도 nodeJS를 복사하기 시작했고 php7을 종료했지만, 쓰레기, 복사만 할 것입니다...
죄송합니다. 위 내용은 제 외설적인 내용입니다~ 위 내용은 순전히 농담이고 유사점은 순전히 우연입니다.
자~ nodeJS의 멀티프로세스를 정식으로 소개하겠습니다~
과거에는 클러스터 자체의 불완전성으로 인해, 아마도 여러 가지 이유로 인해 구현 성능이 좋지 않았습니다. 그 결과 pm2 패키지가 등장했습니다. pm2를 사용하면 여러 프로세스를 쉽게 시작하여 로드 밸런싱을 달성할 수 있습니다.
pm2 start app.js
fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process. The child process and the parent process run in separate memory spaces. At the time of fork() both memory spaces have the same content. Memory writes, file mappings (mmap(2)), and unmappings (munmap(2)) performed by one of the processes do not affect the other.
위 단락은 생성한 프로세스가 실제로 서로 통신하고 마스터 프로세스에 의해 관리될 수 있음을 의미합니다.
사진 보세요~~
실제로는 그런 의미입니다.
좋아요~ 이것은 단지 하위 프로세스를 생성하는 시스템의 모델일 뿐입니다. 그렇다면 NodeJ에서 구현된 프로세스 간의 상호 작용은 어떻게 이루어 집니까?
그러나 통신을 구현하는 것은 어렵지 않습니다. 핵심은 요청 할당에 있습니다. 이는 nodeJS의 큰 함정입니다.
오랜만에
nodeJS의 주인은 처음에는 신이 아니었습니다. 그는 (첩이) 오라고 요청할 때마다 여러 노동자와 작은 황제가 서로 경쟁하는 것을 묵묵히 지켜보았습니다. 그러면 다른 직원들은 그냥 알아서 다음 요청이 오기를 기다리게 될 것이다. 그러므로 요청이 올 때마다 피의 폭풍이 일어날 것입니다. 하지만 우리가 가장 많이 경험한 것은 천둥소리 현상, 즉 CPU가 터지는 현상입니다.
TJ님의 사진을 이용해 설명하겠습니다.
여기서 마스터는 포트만 바인딩하고 들어오는 요청에 대해서는 어떤 처리도 하지 않습니다. 포크된 프로세스에 소켓의 fd를 제공합니다. 그 결과 네 명의 남자(노동자)가 첩(요청)을 강탈했다. 그 장면은 말할 것도 없고 참혹했다.
앞서 언급했듯이 클러스터는 실제로 child_process의 캡슐화 계층이므로 맨 아래 계층으로 계속 진행하겠습니다. 클러스터 다중 프로세스를 구현합니다. 먼저, 이러한 모듈의 기본적인 사용법을 이해해야 합니다. net,child_process.
이것은 nodeJS 프로세스의 핵심 모듈이어야 합니다. 기본적인 방법은 여러 가지가 있지만 여기서는 핵심적인 방법인 스폰(spawn), 포크(fork), 실행(exec)만 소개하겠습니다. 관심이 있으시면 child_process에 가서 참고하실 수 있습니다.
child_process.spawn(명령어, args)
이 방법은 지정된 프로그램을 실행하는 데 사용됩니다. 예:
. 비동기 명령이지만 콜백을 지원하지 않지만 process.on을 사용하여 결과를 모니터링할 수 있습니다. 3개의 매개변수가 제공됩니다.
node app.js
명령: 명령 실행
옵션[객체]: 환경 변수 객체
좋아요~ 간단한 데모를 보여드리겠습니다. 실행해 보세요
touch apawn.js
const spawn = require('child_process').spawn; const touch = spawn('touch',['spawn.js']); touch.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); touch.stderr.on('data', (data) => { console.log(`stderr: ${data}`); }); touch.on('close', (code) => { console.log(`child process exited with code $[code]`); });
을 종료합니다. 그런 다음 디렉터리를 실행하면 Pawn.js 파일이 생성됩니다. 물론 여러 매개변수를 사용하여 명령을 실행해야 하는 경우에는 약간의 어려움이 따릅니다.
따라서 nodeJS는 exec를 사용하여 이를 잘 캡슐화하고 콜백 함수를 지원하므로 우리가 이해하기 쉽습니다. child process exited with code 0
child_process.exec(order,cb(err[,stdout,stderr]));
order:는 실행하는 명령입니다. 예:
cb: 명령이 성공적으로 실행된 후의 콜백 함수입니다. rm spawn.js
正常情况下会删除spawn.js文件。
上面两个只是简单的运行进程的命令。 最后,(Boss总是最后出场的). 我们来瞧瞧fork方法的使用.
fork其实也是用来执行进程,比如,spawn("node",['app.js']),其实和fork('app.js') 是一样的效果的。但是,fork牛逼的地方在于他在开启一个子进程时,同时建立了一个信息通道(双工的哦). 俩个进程之间使用process.on("message",fn)和process.send(...)进行信息的交流.
child_process.fork(order) //创建子进程
worker.on('message',cb) //监听message事件
worker.send(mes) //发送信息
他和spawn类似都是通过返回的通道进行通信。举一个demo, 两个文件master.js和worker.js 来看一下.
//master.js const childProcess = require('child_process'); const worker = childProcess.fork('worker.js'); worker.on('message',function(mes){ console.log(`from worder, message: ${mes}`); }); worker.send("this is master"); //worker.js process.on('message',function(mes){ console.log(`from master, message: ${mes}`); }); process.send("this is worker");
运行,node app.js, 会输出一下结果:
from master, message: this is master from worker, message: this is worker
现在我们已经学会了,如何使用child_process来创建一个基本的进程了。
关于net 这一模块,大家可以参考一下net模块.
ok . 现在我们正式进入,模拟nodeJS cluster模块通信的procedure了。
out of date 的cluster
这里先介绍一下,曾经的cluster实现的一套机理。同样,再放一次图
我们使用net和child_process来模仿一下。
//master.js const net = require('net'); const fork = require('child_process').fork; var handle = net._createServerHandle('0.0.0.0', 3000); for(var i=0;i<4;i++) { fork('./worker').send({}, handle); } //worker.js const net = require('net'); //监听master发送过来的信息 process.on('message', function(m, handle) { start(handle); }); var buf = 'hello nodejs'; ///返回信息 var res = ['HTTP/1.1 200 OK','content-length:'+buf.length].join('\r\n')+'\r\n\r\n'+buf; //嵌套字 function start(server) { server.listen(); var num=0; //监听connection函数 server.onconnection = function(err,handle) { num++; console.log(`worker[${process.pid}]:${num}`); var socket = new net.Socket({ handle: handle }); socket.readable = socket.writable = true; socket.end(res); } }
ok~ 我们运行一下程序, 首先运行node master.js
.
然后使用测试工具,siege.
siege -c 100 -r 2 http://localhost:3000
OK,我们看一下,到底此时的负载是否均衡。
worker[1182]:52 worker[1183]:42 worker[1184]:90 worker[1181]:16
发现,这样任由worker去争夺请求,效率真的很低呀。每一次,触发请求,都有可能导致惊群事件的发生啊喂。所以,后来cluster改变了一种模式,使用master来控制请求的分配,官方给出的算法其实就是round-robin 轮转方法。
高富帅版cluster
现在具体的实现模型就变成这个.
由master来控制请求的给予。通过监听端口,创建一个socket,将获得的请求传递给子进程。
从tj大神那里借鉴的代码demo:
//master const net = require('net'); const fork = require('child_process').fork; var workers = []; for (var i = 0; i < 4; i++) { workers.push(fork('./worker')); } var handle = net._createServerHandle('0.0.0.0', 3000); handle.listen(); //将监听事件移到master中 handle.onconnection = function (err,handle) { var worker = workers.pop(); //取出一个pop worker.send({},handle); workers.unshift(worker); //再放回取出的pop } //worker.js const net = require('net'); process.on('message', function (m, handle) { start(handle); }); var buf = 'hello Node.js'; var res = ['HTTP/1.1 200 OK','content-length:'+buf.length].join('\r\n')+'\r\n\r\n'+buf; function start(handle) { console.log('got a connection on worker, pid = %d', process.pid); var socket = new net.Socket({ handle: handle }); socket.readable = socket.writable = true; socket.end(res); }
这里就经由master来掌控全局了. 当一个皇帝(worker)正在宠幸妃子的时候,master就会安排剩下的几个皇帝排队一个几个的来。 其实中间的handle就会我们具体的业务逻辑. 如同:app.js
.
ok~ 我们再来看一下cluster模块实现多进程的具体写法.
cluster模块实现多进程
现在的cluster已经可以说完全做到的负载均衡。在cluster说明我已经做了阐述了。我们来看一下具体的实现吧
var cluster = require('cluster'); var http = require('http'); var numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log('[master] ' + "start master..."); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('listening', function (worker, address) { console.log('[master] ' + 'listening: worker' + worker.id + ',pid:' + worker.process.pid + ', Address:' + address.address + ":" + address.port); }); } else if (cluster.isWorker) { console.log('[worker] ' + "start worker ..." + cluster.worker.id); var num = 0; http.createServer(function (req, res) { num++; console.log('worker'+cluster.worker.id+":"+num); res.end('worker'+cluster.worker.id+',PID:'+process.pid); }).listen(3000); }
这里使用的是HTTP模块,当然,完全也可以替换为socket模块. 不过由于这样书写,将集群和单边给混淆了。 所以,推荐写法是将具体业务逻辑独立出来.
var cluster = require('cluster'); var numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log('[master] ' + "start master..."); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('listening', function (worker, address) { console.log('[master] ' + 'listening: worker' + worker.id + ',pid:' + worker.process.pid + ', Address:' + address.address + ":" + address.port); }); } else if (cluster.isWorker) { require('app.js'); } //app.js就是开启具体的业务逻辑了 //app.js具体内容 const net = require('net'); //自动创建socket const server = net.createServer(function(socket) { //'connection' listener socket.on('end', function() { console.log('server disconnected'); }); socket.on('data', function() { socket.end('hello\r\n'); }); }); //开启端口的监听 server.listen(8124, function() { //'listening' listener console.log('working') });
接着我们开启服务,node master.js
然后进行测试
siege -c 100 -r 2 http://localhost:8124
我这里开启的是长连接. 每个worker处理的长连接数是有限的。所以,当有额外的连接到来时,worker会断开当前没有响应的连接,去处理新的连接。
不过,平常我们都是使用HTTP开启 短连接,快速处理大并发的请求。
这是我改成HTTP短连接之后的结果
Transactions: 200 hits Availability: 100.00 % Elapsed time: 2.09 secs Data transferred: 0.00 MB Response time: 0.02 secs Transaction rate: 95.69 trans/sec Throughput: 0.00 MB/sec Concurrency: 1.74 Successful transactions: 200 Failed transactions: 0 Longest transaction: 0.05 Shortest transaction: 0.02
那,怎么模拟大并发嘞?
e e e e e e e e e ...
自己解决啊~
开玩笑的啦~ 不然我写blog是为了什么呢? 就是为了传播知识.
在介绍工具之前,我想先说几个关于性能的基本概念
QPS(TPS),并发数,响应时间,吞吐量,吞吐率
你母鸡的性能测试theories
自从我们和服务器扯上关系后,我们前端的性能测试真的很多。但这也是我们必须掌握的tip. 本来前端宝宝只需要看看控制台,了解一下网页运行是否运行顺畅, 看看TimeLine,Profile 就可以了。 不过,作为一名有追求,有志于改变世界的童鞋来说。。。
md~ 又要学了...
ok~ 好了,在进入正题之前,我再放一次 线上的测试结果.
Transactions: 200 hits Availability: 100.00 % Elapsed time: 13.46 secs Data transferred: 0.15 MB Response time: 3.64 secs Transaction rate: 14.86 trans/sec Throughput: 0.01 MB/sec Concurrency: 54.15 Successful transactions: 200 Failed transactions: 0 Longest transaction: 11.27 Shortest transaction: 0.01
根据上面的数据,就可以得出,你网页的大致性能了。
恩~ let's begin
吞吐率
关于吞吐率有多种解读,一种是:描绘web服务器单位时间处理请求的能力。根据这个描述,其单位就为: req/sec. 另一种是: 单位时间内网络上传输的数据量。 而根据这个描述的话,他的单位就为: MB/sec.
而这个指标就是上面数据中的Throughput. 当然,肯定是越大越好了
吞吐量
这个和上面的吞吐率很有点关系的。 吞吐量是在没有时间的限制下,你一次测试的传输数据总和。 所以,没有时间条件的测试,都是耍流氓。
这个对应于上面数据中的Data transferred.
事务 && TPS
熟悉数据库操作的童鞋,应该知道,在数据库中常常会提到一个叫做事务的概念。 在数据库中,一个事务,常常代表着一个具体的处理流程和结果. 比如,我现在想要的数据是 2013-2015年,数学期末考试成绩排名. 这个就是一个具体的事务,那么我们映射到数据库中就是,取出2013-2015年的排名,然后取平均值,返回最后的排序结果。 可以看出,事务并不单单指单一的操作,他是由一个或一个以上 操作组合而成具有 实际意义的。 那,反映到前端测试,我们应该怎样去定义呢? 首先,我们需要了解,前端的网络交流其实就是 请求-响应模式. 也就是说,每一次请求,我们都可以理解为一次事务(trans).
所以,TPS(transaction per second)就可以理解为1sec内,系统能够处理的请求数目.他的单位也就是: trans/sec . 你当然也可以理解为seq/sec.
所以说,TPS 应该是衡量一个系统承载力最优的一个标识.
TPS的计算公式很容易的出来就是: Transactions / Elapsed time
.
不过, 凡事无绝对。 大家以后遇到测试的时候,应该就会知道的.
并发数
就是服务器能够并发处理的连接数,具体我也母鸡他的单位是什么。 官方给出的解释是:
Concurrency is average number of simultaneous connections, a number which rises as server performance decreases.
这里我们就理解为,这就是一个衡量系统的承载力的一个标准吧。 当Concurrency 越高,表示 系统承载的越多,但性能也越低。
ok~ 但是我们如何利用这些数据,来确定我们的并发策略呢? e e e e e e e ...
当然, 一两次测试的结果真的没有什么卵用. 所以实际上,我们需要进行多次测试,然后画图才行。 当然,一些大公司,早就有一套完整的系统来计算你web服务器的瓶颈,以及 给出 最优的并发策略.
废话不多说,我们来看看,如何分析,才能得出 比较好的 并发策略。
探究并发策略
首先,我们这里的并发需要进行区分. 一个是并发的请求数,一个是并发的用户数. 这两个对于服务器是完全不同的需求。
假如100个用户同时向服务器分别进行10次请求,与1个用户向服务器连续进行1000次请求。两个的效果一样么?
一个用户向服务器连续进行1000次请求的过程中,任何时刻服务器的网卡接受缓存区中只有来自该用户的1个请求,而100个用户同时向服务器分别进行10次请求的过程中,服务器网卡接收缓冲区中最多有100个等待处理的请求,显然这时候服务器的压力更大。
所以上面所说的 并发用户数和吞吐率 是完全不一样的.
不过通常来说,我们更看重的是Concurrency(并发用户数). 因为这样更能反映出系统的 能力。 一般,我们都会对并发用户数进行一些限制,比如apache的maxClients参数.
ok~ 我们来实例分析一下吧.
首先,我们拿到一份测试数据.
接着,我们进行数据分析.
根据并发数和吞吐率的关系得出下列的图.
OK~ 我们会发现从大约130并发数的地方开始,吞吐率开始下降,而且越多下降的越厉害。 主要是因为,在前面部分随着用户数的上升,空闲的系统资源得到充分的利用,当然就和正太曲线一样,总会有个顶点。 当到达一定值后,顶点就会出现了. 这就我们的系统的一个瓶颈.
接着,我们细化分析,响应时间和并发用户数的相关性
同样额道理,当并发数到达130左右,正对每个req的响应时间开始增加,越大越抖,这适合吞吐率是相关的。 所以,我们可以得出一个结论,该次连接 并发数 最好设置为100~150之间。 当然,这样的分析很肤浅,不过,对于我们这些前端宝宝来说了解一下就足够了。
接下来,我们使用工具来武装自己的头脑.
这里主要介绍一个测试工具,siege.
并发测试工具
事实上并发测试工具主要有3个siege,ab,还有webbench. 我这里之所以没介绍webbench的原因,因为,我在尝试安装他时,老子,电脑差点就挂了(我的MAC pro)... 不过后面,被聪明的我 巧妙的挽回~ 所以,如果有其他大神在MAC x11 上成功安装,可以私信小弟。让我学习学习。
ok~ 吐槽完了。我们正式说一下siege吧
siege
安装siege利用MAC神器 homebrew, 就是就和js前端世界的npm一样.
安装ing:
brew install siege
安装成功--bingo
接着,我们来看一下语法吧.
-c NUM 设置并发的用户数量.eg: -c 100;
-r NUM 设置发送几轮的请求,即,总的请求数为: -cNum*-rNum
但是, -r不能和-t一起使用(为什么呢?你猜).eg: -r 20
-t NUM 测试持续时间,指你运行一次测试需要的时间,在timeout后,结束测试.
-f file. 用来测试file里面的url路径 eg: -f girls.txt
.
-b . 就是询问开不开启基准测试(benchmark)。 这个参数不太重要,有兴趣的同学,可以下去学习一下。
关于-c -r我就不介绍了。 大家有兴趣,可以参考一下,我前一篇文章让你升级的网络知识. 这里主要介绍一下 -f 参数.
通常,如果我们想要测试多个页面的话,可以新建一个文件,在文件中创建 你想测试的所有网页地址.
比如:
//文件名为 urls.txt
www.example.com www.example.org 123.45.67.89
然后运行测试
siege -f your/file/path.txt -c 100 -t 10s
OK~ 关于进程和测试的内容就介绍到这了。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

이 기사는 NodeJS V8 엔진의 메모리 및 가비지 수집기(GC)에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다.

Non-Blocking, Event-Driven 기반으로 구축된 Node 서비스는 메모리 소모가 적다는 장점이 있으며, 대규모 네트워크 요청을 처리하는데 매우 적합합니다. 대규모 요청을 전제로 '메모리 제어'와 관련된 문제를 고려해야 합니다. 1. V8의 가비지 수집 메커니즘과 메모리 제한 Js는 가비지 수집 기계에 의해 제어됩니다.

동시성 프로그래밍 언어인 Golang의 내장 코루틴 메커니즘과 멀티스레드 작업은 가벼운 멀티태스킹을 가능하게 합니다. 그러나 다중 프로세스 처리 시나리오에서는 서로 다른 프로세스 간의 통신 및 공유 메모리가 프로그램 개발의 주요 문제가 되었습니다. 이번 글에서는 Golang에서 여러 프로세스 간 공유 메모리를 구현하는 응용 방법을 소개합니다. 1. Golang에서 다중 프로세스 구현 방법 Golang에서는 다중 프로세스 동시 처리를 포크(fork), os.Process,

파일 모듈은 파일 읽기/쓰기/열기/닫기/삭제 추가 등과 같은 기본 파일 작업을 캡슐화한 것입니다. 파일 모듈의 가장 큰 특징은 모든 메소드가 **동기** 및 ** 두 가지 버전을 제공한다는 것입니다. 비동기**, sync 접미사가 있는 메서드는 모두 동기화 메서드이고, 없는 메서드는 모두 이기종 메서드입니다.

이벤트 루프는 Node.js의 기본 부분이며 메인 스레드가 차단되지 않도록 하여 비동기 프로그래밍을 가능하게 합니다. 이벤트 루프를 이해하는 것은 효율적인 애플리케이션을 구축하는 데 중요합니다. 다음 기사는 Node.js의 이벤트 루프에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다!

노드가 npm 명령을 사용할 수 없는 이유는 환경 변수가 올바르게 구성되지 않았기 때문입니다. 해결 방법은 다음과 같습니다. 1. "시스템 속성"을 엽니다. 2. "환경 변수" -> "시스템 변수"를 찾은 다음 환경을 편집합니다. 3. nodejs 폴더의 위치를 찾습니다. 4. "확인"을 클릭합니다.

초기에 JS는 브라우저 측에서만 실행되었습니다. 유니코드로 인코딩된 문자열은 처리하기 쉬웠지만 바이너리 및 유니코드가 아닌 인코딩된 문자열을 처리하는 것은 어려웠습니다. 그리고 바이너리는 컴퓨터의 가장 낮은 데이터 형식인 비디오/오디오/프로그램/네트워크 패키지입니다.

프론트 엔드 애플리케이션 개발에 Node.js를 사용하는 방법은 무엇입니까? 다음 기사에서는 프레젠테이션 계층 애플리케이션 개발과 관련된 Node에서 프런트 엔드 애플리케이션을 개발하는 방법을 소개합니다. 오늘 제가 공유한 솔루션은 간단한 시나리오를 위한 것입니다. 이는 프런트 엔드 개발자가 코딩이 없더라도 Node.js에 대한 배경 지식과 전문 지식을 너무 많이 습득하지 않고도 간단한 서버 측 개발 작업을 완료할 수 있도록 설계되었습니다. 경험.
