本篇文章为大家展示了nodejs中怎么利用cluster实现多进程,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
cluster
属性和方法
isMaster属性,返回是不是主进程,boolean值;
isWorker属性, 返回该进程是不是工作进程;
fork()方法,只能通过主进程调用,衍生出一个新的worker子进程,返回worker对象;
setupMaster([setting])方法,用于修改fork的默认行为,一旦调用,将会按照cluster.settings进行设置;
settings属性;用于配置;
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('子说:你好');
}
事件
fork事件,当新的工作进程被fork时触发,可以用来记录工作进程活动;
listening事件,当一个工作进程调用listen()后触发,事件处理器两个参数:worker:工作进程对象, address:包含了链接属性
message事件,监听子进程的消息;当cluster主进程接收任何工作进程发送的消息时触发;
online事件,
disconnect事件,当工作进程断开时调用;
exit事件,
setup事件,cluster.setupMaster()执行后触发;
cluster多进程模型
那通过child_process.fork()直接创建不就可以了,为什么要通过cluster
这种方式只实现了多进程,多进程运行还涉及父子进程通信,子进程管理,以及负载均衡等问题,这些特性cluster已经做了处理了;
惊群现象
master.js
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.js
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);
};
}
nginx proxy
守护进程:退出命令窗口之后,服务一直处于运行状态;
cluster多进程调度模型
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);
}
cluster中的优雅退出
关闭异常worker进程所有的TCP server(将已有的快速断开,且不再接受新的连接),断开和Master的IPC通道,不再接受新的用户请求;
Master立刻fork一个新的worker进程,保证总的进程数量不变;
异常worker等待一段时间,处理完已接受的请求后退出;
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();
})
IPC通信
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);
})
}
上述内容就是nodejs中怎么利用cluster实现多进程,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注天达云行业资讯频道。