Skip to content

node的原生cluster模块 #56

@Wscats

Description

@Wscats

主进程和子进程

const cluster = require('cluster');
if (cluster.isMaster) {
  console.log('这是主进程');
  cluster.fork();
  cluster.fork();
} else if (cluster.isWorker) {
  console.log(`这是工作进程 #${cluster.worker.id}`);
}
  • 在主进程中 cluster 表示主进程(用于监听、发送事件), process 是本身的进程,worker 表示子进程,通过 cluster.workers 获取
  • 在子进程中 process 表示子进程(用于监听、发送事件),也可以通过 cluster.worker 表示当前子进程
    cluster.worker.process 等价于 process(在子进程中)
const cluster = require('cluster');
const http = require('http');
console.log(cluster.isMaster); // 这里如果我电脑是八核,则会打印一个true,七个false
// 一个主进程 判断是否主进程
if (cluster.isMaster) {
    // 跟踪 http 请求。
    let numReqs = 0;
    setInterval(() => {
        console.log(`请求的数量 = ${numReqs}`);
    }, 1000);
    // 对请求计数。
    function messageHandler(msg) {
        if (msg.cmd && msg.cmd === 'notifyRequest') {
            numReqs += 1;
        }
    }
    // 启动 worker 并监听包含 notifyRequest 的消息。
    // 循环查找电脑核心,分配进程
    const numCPUs = require('os').cpus().length;
    for (let i = 0; i < numCPUs; i++) {
        // 生成多个工作进程(子进程)
        cluster.fork();
    }
    for (const id in cluster.workers) {
        // 监听工作进程发过来的信息
        cluster.workers[id].on('message', messageHandler);
    }
// 多个工作进程
} else {
    // 工作进程有一个 http 服务器。
    http.Server((req, res) => {
        res.writeHead(200);
        res.end('你好世界\n');
        // 通知主进程接收到了请求。
        process.send({ cmd: 'notifyRequest' });
    }).listen(8000);
}

屏幕快照 2019-09-09 上午8 36 28

  • cluster 用于监听 process(child) 子进程触发的各种事件
  • worker 在主进程中获取,用于和自身通信。当子进程触发事件时,会返回当前的 worker 以及相关的信息到主进程相应的事件中
  • process(parent) 主进程本身的进程实例,在通信过程中基本没有用到
  • process(child) 子进程本身的实例,只能在子进程获取用于监听自身的事件

可见主进程与子进程通过这样一个三角关系互相通信,其中 cluster 和 worker 是在主进程中获取的,process(child) 是子进程。 cluster 通过操作 worker 通知子进程,子进程本身和 cluster 进行通信。为什么要这样设计呢?因为子进程会有多个,只有通过 worker 才能选择和哪个进程通信。

遍历所有子进程

for (const id in cluster.workers) {
    callback(cluster.workers[id]);
}

通信

主进程全局监听来自子进程的信息

// 全局监听
cluster.on('message', (worker, msg) => {
    console.log(msg)
})
// 遍历所有子进程监听
for (const id in cluster.workers) {
    // 监听工作进程发过来的信息
    cluster.workers[id].on('message', messageHandler);
}

子进程主动触发事件,与主进程通信

process.send({
    cmd: 'notifyRequest',
    msg: 'hi'
}, () => {
    console.log('send')
});

主进程主动和子进程通信

const cluster = require('cluster');
if (cluster.isMaster) {
    const worker = cluster.fork();
    setInterval(() => {
        worker.send('你好');
    }, 1000)
} else if (cluster.isWorker) {
    process.on('message', (msg) => {
        console.log(msg)
        process.send(msg);
    });
}

伪造多请求

可以使用多个子进程发送数据,伪造请求:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);
  // 衍生工作进程。
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 工作进程可以共享任何 TCP 连接。
  // 在本例子中,共享的是 HTTP 请求。
  http.get('http://www.baidu.com/', (res) => {
    console.log(res.statusCode)
  })
  console.log(`工作进程 ${process.pid} 已启动`);
}

参考文档

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions