nodeJS 是一门单线程!异步!非阻塞语言! 单CPU
pm2的内部和cluster内部实现其实是一个道理,都是封装了一层child_process--fork. 而child_process--fork 则是封装了unix 系统的fork 方法。
nodeJS的master 开始并不是上帝, 他只是一个小小的太监,每次请求(妃子)来的时候,他只会默默的看着几个worker小皇帝相互争夺,如果某个worker胜出,则其他的worker也就草草了事,等下一个请求过来。所以说,每来一次请求,都会引起一场腥风血雨。而,我们体会最深的就是惊群现象,即,CPU爆表.
由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);
}
现在的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);
}