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); }) }