我们都知道 Node
是一个 single thread
并且非同步的语言,
那...假使面临排山倒海的使用者请求时你能想像那一个 thread
孤军奋战的感受吗?
没有 ! 你只想到你自己。(好久以前的梗)
所以后来官方提出了这个模组,好让你可以开启更多的 process
去减轻那个可怜 Thread
的负担~
避免以下经典动图的发生。
这让我想到我上一支手机 Sony Z5P 拥有当年的旗舰 CPU ,在游戏效能上根本烂到炸,标榜八核心但是实际上只有 4 颗小核心在跑 ,只有在跑分的时候另外四颗大核心才会抛头露面刷存在感... (后来以 Root 自行改设定才解决)
此篇学习目标 ◑ω◐ :
Cluster
他怎么运作的实战在 Hello World使用 pm2
让管理 cluster
更容易Cluster
他怎么运作的?
他主要是使用 child_process.fork()
产生新的 proccess 藉此与父进程沟通。
而 Cluster 由两种分配方式决定如何分配进来的请求。
而这两种都是经由 master process 倾听一个 port
然后分配到不同的 process
。
如图所示
第一种配发方式
The first one (and the default one on all platforms except Windows), is the round-robin approach, where the master process listens on a port, accepts new connections and distributes them across the workers in a round-robin fashion, with some built-in smarts to avoid overloading a worker process.
是经由 round-robin approach 来决定 ,简单来说就有点像是老师分派值日生擦黑板,前提是一天只有一件事就是擦黑板且一天只需要擦一次就可以换下一个人。
所以就是当一个请求进来的时候进到 master process
然后由他去轮流指派 一个 process
的概念。(有错或是举例错误请纠正我)
Note:
除了Windows
之外其余都是预设第一种配发方式。
就你最特别这样。
第二种配发方式
The second approach is where the master process creates the listen socket and sends it to interested workers. The workers then accept incoming connections directly.
简单来说一样是由 master process
监听接口,然后直接配发到有兴趣的 process
,就是谁有兴趣就配给谁。
在现实生活中感觉可以徵求意见,但是在这边其实我不知道这个机制要如何知道谁有兴趣谁没兴趣,如果有人知道的可以跟我分享一下实际案例,感恩。
如果你也不知道也没关係我看完也是一个...
官方还特地说明了第二种配发方式
The second approach should, in theory, give the best performance. In practice however, distribution tends to be very unbalanced due to operating system scheduler vagaries. Loads have been observed where over 70% of all connections ended up in just two processes, out of a total of eight.
理论上,第二种方式效能会是最好的,但是实际上会造成其实负载平衡很不平衡的状况,假使在高併发的情况下总共有八个 process
但却会有 70%
的连线都只会落在两个 proccess
在处理。
让我感觉到能者过劳死
的悲痛。
俗话说的好...
你强,你来。
实战在 Hello World
我们用之前 第二篇 写的 Hello world 和官方给的範例来实测看看差别。
我这边使用 loadtest 这工具来简单测试一下。
single thread
实测结果: 平均 22 ms
的处理时间
cluster multi-core systems
官方 Hello world 範例
const cluster = require('cluster');const http = require('http');const numCPUs = require('os').cpus().length;if (cluster.isMaster) { console.log(`Master ${process.pid} is running`); // Fork workers. for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`worker ${worker.process.pid} died`); });} else { // Workers can share any TCP connection // In this case it is an HTTP server http.createServer((req, res) => { res.writeHead(200); res.end('hello world\n'); }).listen(8000); console.log(`Worker ${process.pid} started`);}
实测结果: 平均 26.9 ms
的处理时间
嗯...
跟我想像中的结果不一样啊啊啊啊啊! 目前我还在寻找这未知的谜题...
目前我的猜测是因为其实他一下就做完了,然后我开了 cluster 导致他要花时间去分配,造成处理时间更长。
另外看了 stack overflow 的这个讨论串
Node.js clustering is slower than single threaded mode
但是还是有点违背我的想像 ~~
如果你知道为什么拜託告诉我。
使用 pm2
让管理 cluster
更容易
我另外看了一下好像大多数人不会直接使用原生的 cluster 而是使用这个 pm2 因为设定简单,然后...好像弄的很不错(?)
用法很简单就是pm2 start -i <数量> --name <tagName> <path>
然后我再次的挑战上面那个谜题
详细用法我这边就不再赘述有兴趣可以自行看官方文件唷~
实测结果: 平均 13.4 ms
的处理时间
这才是我要的结果xDDD
至于原因嘛...可能是还有更多设定方面和处理其实不太一样,导致效能受影响(?)
所以我觉得...嗯...我还是直接用 pm2 好了 (X
如果有兴趣研究的可以跟我说...我可以听你的研究成果 xD
结语
另外看到满多人提说其实很不建议使用这种方式来做 load balance
,原因是如上面所讲的这个机制是透过 master process
来倾听一个 port 再去分配 worker ,那其实透过 Nginx 来做 LB 然后还有各自的 port 效能来得更优异。
我发现之后开开心心的想说可以用在我前几週发的麦当劳报报自动领取的 server,殊不知我一看我 aws 的目前使用配置...
没错...就是
1
配个...毛? XDDD
感谢收看。