Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node的原生cluster模块 #56

Open
Wscats opened this issue Sep 9, 2019 · 0 comments
Open

node的原生cluster模块 #56

Wscats opened this issue Sep 9, 2019 · 0 comments

Comments

@Wscats
Copy link
Owner

Wscats commented Sep 9, 2019

主进程和子进程

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} 已启动`);
}

参考文档

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant