node的原生cluster模块
# 主进程和子进程

```js
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(在子进程中)

```js
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);
}
```
<img width="1129" alt="屏幕快照 2019-09-09 上午8 36 28" src="https://user-images.githubusercontent.com/17243165/64497017-404e7600-d2dd-11e9-9086-6bcf71ae8568.png">

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

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

# 遍历所有子进程

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

# 通信

主进程全局监听来自子进程的信息
```js
// 全局监听
cluster.on('message', (worker, msg) => {
    console.log(msg)
})
// 遍历所有子进程监听
for (const id in cluster.workers) {
    // 监听工作进程发过来的信息
    cluster.workers[id].on('message', messageHandler);
}
```
子进程主动触发事件，与主进程通信
```js
process.send({
    cmd: 'notifyRequest',
    msg: 'hi'
}, () => {
    console.log('send')
});
```
主进程主动和子进程通信
```js
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);
    });
}
```

# 伪造多请求

可以使用多个子进程发送数据，伪造请求：
```js
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} 已启动`);
}
```

# 参考文档

- [Node的官方文档cluster模块](http://nodejs.cn/api/cluster.html)
- [MrTreasure/Algorithm
](https://github.com/MrTreasure/Algorithm/tree/master/src/cluster)