目標
- 在主進程中完成以下事情:
- 每隔1秒鐘輸出,當前請求的數量
- 創建等同于CPU數量的進程
- 對每個進程施加一個處理函數,用于統計請求的數量
- 在各個CPU的進程中完成以下事情
- 監聽8000端口的請求,并返回最簡單的信息
- 發送事件,以觸發主進程中施加的事件處理函數
前置知識
- process.pid
在主進程cluster.isMaster
中,process.id
是主進程的id
在工作進程(子進程)cluster.isWorker
中,process.id
是工作進程(子進程)的id
- 獲取cpu的數量
const numCPUs = require('os').cpus().length;
- 判斷一個進程是否為主進程
const cluster = require('cluster');
if(cluster.isMaster) { ... }
- 創建一個新進程
const cluster = require('cluster');
const work = cluster.fork();
實現
const cluster= require('cluster');
const http = require('http');if(cluster.isMaster) {// 主進程let count = 0;// 每隔1秒鐘,就輸出當前的訪問次數setInterval(()=>{console.log(`訪問次數為: ${count}`)}, 1000);let numCPUs = require('os').cpus().length;for(let i =0 ; i < numCPUs ; i++) {cluster.fork(); // 創建等同于cpu核數的進程}for(let id in cluster.workers){cluster.workers[id].on('message', (msg) =>{if(msg.cmd && msg.cmd === 'notifyRequest') {count++;}})}
} else {// 子進程http.Server((req, res) => {if(req.url !== '/favicon.ico') {res.writeHead(200);res.end('Hi Marron');// 通知執行 cmd.notifyRequest 事件process.send({cmd: 'notifyRequest'});}}).listen(8000)
}
擴展
- 由于node.js是單線程.很容易卡死而導致崩潰.如下
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) =>{aaa();await next();ctx.body = 'marron';
});
app.listen(3000);
- 說明會直接報錯
ReferenceError: aaa is not defined
,會直接退出當前進程. - 思路: 可以在主進程中監聽,一旦發現有進程死亡,就開啟新的進程.
綜上所述,明確在主進程中的目標:
- 開啟等同于CPU核數的進程,并將進程保存在進程組(workers)對象中.
- 監聽進程的死亡,一旦發現.就創建新的進程,并將新的進程替換掛掉的那個進程
子進程:
- 創建一個http服務器監聽3000端口
- 當訪問該端口時,以一定的幾率報錯(讓當天進程死亡).
const cluster = require('cluster');
const os = require('os');
const numCPUs = os.cpus().length;
const process = require('process');// 保存進程組的對象
const workers = {};
if(cluster.isMaster) {// 主進程for(let i = 0; i< numCPUs; i++){const worker = cluster.fork(); // 創建一個進程workers[worker['pid']] = worker; // 保存當前進程}cluster.on('death', function(worker){// 監聽進程的死亡nWorker = cluster.fork(); // 新建進程workers[worker.pid] = nWorker;})
} else {const Koa = require('koa');const app = new Koa();app.use(async (ctx, next) => {Math.random > 0.95 ? aaa() : ''; // 手動掛掉進程console.log(`current process ${process.pid}`);await next();ctx.body = 'marron';})app.listen(3000);
}
當掛的時候,自動重新啟動當前服務