const cluster = require('cluster'); const cpuNums = require('os').cpus().length; const http = require('http'); if (cluster.isMaster) { console.log(cpuNums); for (var i = 0; i < cpuNums; i++) { cluster.fork(); // 至关于node main.js,从新执行本身 // 和process_child相比,不用从新建立child.js, } cluster.on('fork', worker => { console.log(`主进程fork了一个worker,pid为${worker.process.pid}`) }) cluster.on('listening', worker => { console.log(`主进程fork了一个worker,pid为${worker.process.pid}`) }) cluster.on('message', data => { console.log('主进程接收到了子进程消息为:',data) }) Object.keys(cluster.workers).forEach(item => { cluster.workers[item].on('message', data => { console.log(data); }); }); cluster.on('disconnect', (worker) => { console.log('有工做进程退出了',worker.process.pid) }) } else { http.createServer((req, res) => { res.end('hello') }).listen(8001, () =>{ console.log('child server is runing') }) console.log('我是子进程'); process.send('子说:你好'); }
那经过child_process.fork()直接建立不就能够了,为何要经过clustercss
这种方式只实现了多进程,多进程运行还涉及父子进程通讯,子进程管理,以及负载均衡等问题,这些特性cluster已经作了处理了;html
master.jsnode
const net = require('net'); // 是最基础的网络模块,http的基础就是网络模块,最底层是socket const fork = require('child_process').fork; // 惊群 var handle = net._createServerHandle('0.0.0.0', 5000); // net模块建立一个服务,绑定到3000端口,返回一个callback for (var i = 0; i < 4; i++) { console.log('fork', i); fork('./worket.js').send({}, handle); // 主进程fork子进程,send信息 }
worker.jsnginx
const net = require('net'); process.on('message', (m, handle) => { // 子进程接收到master信息 // master接收客户端的请求,worker去响应 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; var data = {}; function start(server) { // 响应逻辑,重点关注惊群效果,计数 server.listen(); server.onconnection = function(err, hand) { var pid = process.pid; if (!data[pid]) { data[pid] = 0; } data[pid]++; console.log('get a connection on worker,pid = %d', process.pid, data[pid]); var socket = net.Socket({ handle: hand }); socket.readable = socket.writable = true; // 修改socket的读写属性 socket.end(res); }; }
守护进程:退出命令窗口以后,服务一直处于运行状态;算法
round-robin 轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器;服务器
cluster-model.js网络
const net = require('net'); const fork = require('child_process').fork; // cluster 简单版本,cluster就是基于child_process去封装的; var workers = []; for (var i = 0; i < 4; i++) { workers.push(fork('./child')); // cluster workers } var handle = net._createServerHandle('0.0.0.0', 3001); // master handle.listen(); handle.onconnection = function(err, handle) { var worker = workers.pop(); worker.send({}, handle); workers.unshift(worker); // 经过pop 和 unshift实现一个简单的轮询 };
child.js并发
const net = require('net'); process.on('message', (m, handle) => { debugger; start(handle); }); var buf = 'hello cluster'; var res = ['HTTP/1.1 200 OK', 'content-length' + buf.length].join('\r\n') + '\r\n\r\n' + buf; function start(handle) { console.log('get a worker on server,pid = ' + process.pid); var socket = net.Socket({ handle }); socket.readable = socket.writable = true; // 修改socket的读写属性 socket.end(res); }
if(cluster.isMaster){ cluster.fork(); }else { // 出错以后 try{ res.end(dddd); // 报错,整个线程挂掉,不能提供服务, }catch(err){ // 断开链接,断开和Master的链接,守护进程其实就是重启; process.disconnect(); // or exit() } }
cluster.on('exit',function(){ cluster.fork(); }) cluster.on('disconnect',function(){ cluster.fork(); })
const cluster = require('cluster'); if(cluster.isMaster){ var worker = cluster.fork(); worker.send('hi, i am master'); worker.on('message', (msg) =>{ console.log(`${msg} is from worker ${worker.id}`) }) }else if(cluster.isWorker){ process.on('message', (msg) =>{ process.send(msg); }) }