首頁  >  文章  >  web前端  >  聊聊Nodejs-cluster模組,介紹一下其使用方法

聊聊Nodejs-cluster模組,介紹一下其使用方法

青灯夜游
青灯夜游轉載
2021-12-13 18:44:021998瀏覽

本篇文章帶大家了解一下node中的Nodejs-cluster模組,介紹一下Nodejs-cluster模組的用法,希望對大家有幫助!

聊聊Nodejs-cluster模組,介紹一下其使用方法

面試官有時候會問你,你給我說下nodejs如何開啟多進程哇,你腦海裡就應該立刻出現cluster模組,如今讓我帶你去探討下cluster模組的使用。

基本用法

Node.js預設單一進程運行,對於32位元系統最高可以使用512MB內存,對於64位元最高可以使用1GB記憶體。對於多核心CPU的電腦來說,這樣做效率很低,因為只有一個核心在運行,其他核心都在閒置。 cluster模組就是為了解決這個問題而提出的。

cluster模組允許設立一個主進程和若干個worker進程,由主進程監控和協調worker進程的運作。 worker之間採用進程間通訊交換訊息,cluster模組內建負載平衡器,採用Round-robin演算法協調各個worker進程之間的負載。運行時,所有新建立的連結都由主進程完成,然後主進程再把TCP連線分配給指定的worker進程。

var cluster = require('cluster');
var os = require('os');

if (cluster.isMaster){
  for (var i = 0, n = os.cpus().length; i < n; i += 1){
    cluster.fork();
  }
} else {
  http.createServer(function(req, res) {
    res.writeHead(200);
    res.end("hello world\n");
  }).listen(8000);
}

上面程式碼先判斷目前進程是否為主進程(cluster.isMaster),如果是的,就依照CPU的核數,新建若干個worker進程;如果不是,表示當前進程是worker進程,則在該進程啟動一個伺服器程式。

上面這段程式碼有一個缺點,就是一旦work進程掛了,主程式無法知道。為了解決這個問題,可以在主行程部署online事件和exit事件的監聽函式。

var cluster = require(&#39;cluster&#39;);

if(cluster.isMaster) {
  var numWorkers = require(&#39;os&#39;).cpus().length;
  console.log(&#39;Master cluster setting up &#39; + numWorkers + &#39; workers...&#39;);

  for(var i = 0; i < numWorkers; i++) {
    cluster.fork();
  }

  cluster.on(&#39;online&#39;, function(worker) {
    console.log(&#39;Worker &#39; + worker.process.pid + &#39; is online&#39;);
  });

  cluster.on(&#39;exit&#39;, function(worker, code, signal) {
    console.log(&#39;Worker &#39; + worker.process.pid + &#39; died with code: &#39; + code + &#39;, and signal: &#39; + signal);
    console.log(&#39;Starting a new worker&#39;);
    cluster.fork();
  });
}

上面程式碼中,主行程一旦監聽到worker行程的exit事件,就會重新啟動一個worker行程。 worker流程一旦啟動成功,可以正常運作了,就會發出online事件。

worker物件

worker物件是cluster.fork()的回傳值,代表一個worker進程。

它的屬性和方法如下。

(1)worker.id

worker.id傳回目前worker的獨一無二的行程編號。這個編號也是cluster.workers中指向目前流程的索引值。

(2)worker.process

所有的worker行程都是用child_process.fork()產生的。 child_process.fork()返回的對象,就被保存在worker.process之中。透過這個屬性,可以取得worker所在的進程物件。

(3)worker.send()

此方法用於在主進程中,向子進程發送訊息。

if (cluster.isMaster) {
  var worker = cluster.fork();
  worker.send(&#39;hi there&#39;);
} else if (cluster.isWorker) {
  process.on(&#39;message&#39;, function(msg) {
    process.send(msg);
  });
}

上面程式碼的作用是,worker程式對主行程發出的每個訊息,都做迴聲。

在worker進程中,要向主程序發送訊息,使用process.send(message);要監聽主程序發出的訊息,使用下面的程式碼。

process.on(&#39;message&#39;, function(message) {
  console.log(message);
});

發出的訊息可以字串,也可以是JSON物件。下面是一個發送JSON物件的例子。

worker.send({
  type: &#39;task 1&#39;,
  from: &#39;master&#39;,
  data: {
    // the data that you want to transfer
  }
});

cluster.workers物件

#該物件只有主流程才有,包含了所有worker進程。每個成員的鍵值就是一個worker進程對象,鍵名就是該worker進程的worker.id屬性。

function eachWorker(callback) {
  for (var id in cluster.workers) {
    callback(cluster.workers[id]);
  }
}
eachWorker(function(worker) {
  worker.send(&#39;big announcement to all workers&#39;);
});

上面程式碼用來遍歷所有worker進程。

目前socket的data事件,也可以用id屬性辨識worker行程。

socket.on(&#39;data&#39;, function(id) {
  var worker = cluster.workers[id];
});

cluster模組的屬性與方法

#isMaster,isWorker

isMaster屬性傳回一個布林值,表示目前進程是否為主進程。這個屬性由process.env.NODE_UNIQUE_ID決定,如果process.env.NODE_UNIQUE_ID為未定義,就表示該進程是主進程。

isWorker屬性傳回一個布林值,表示目前進程是否為work進程。它與isMaster屬性的值正好相反。

fork()

fork方法用來新建一個worker程序,上下文都複製主程序。只有主進程才能呼叫這個方法。

該方法傳回一個worker物件。

kill()

kill方法用來終止worker程式。它可以接受一個參數,表示系統訊號。

如果目前是主進程,就會終止與worker.process的聯絡,然後將系統訊號法發送到worker進程。如果目前是worker進程,就會終止與主進程的通信,然後退出,返回0。

在先前的版本中,該方法也稱為 worker.destroy() 。

listening事件

worker程序呼叫listening方法以後,「listening」事件就傳到該行程的伺服器,然後傳向主程序。

該事件的回呼函數接受兩個參數,一個是目前worker對象,另一個是位址對象,包含網址、連接埠、位址類型(IPv4、IPv6、Unix socket、UDP)等資訊。這對於那些服務多個網址的Node應用程式非常有用。

不中斷地重啟Node服務

重启服务需要关闭后再启动,利用cluster模块,可以做到先启动一个worker进程,再把原有的所有work进程关闭。这样就能实现不中断地重启Node服务。

首先,主进程向worker进程发出重启信号。

workers[wid].send({type: &#39;shutdown&#39;, from: &#39;master&#39;});

worker进程监听message事件,一旦发现内容是shutdown,就退出。

process.on(&#39;message&#39;, function(message) {
  if(message.type === &#39;shutdown&#39;) {
    process.exit(0);
  }
});

下面是一个关闭所有worker进程的函数。

function restartWorkers() {
  var wid, workerIds = [];
  for(wid in cluster.workers) {
    workerIds.push(wid);
  }

  workerIds.forEach(function(wid) {
    cluster.workers[wid].send({
      text: &#39;shutdown&#39;,
      from: &#39;master&#39;
     });
    setTimeout(function() {
      if(cluster.workers[wid]) {
        cluster.workers[wid].kill(&#39;SIGKILL&#39;);
      }
    }, 5000);
  });
};

PM2模块

PM2模块是cluster模块的一个包装层。它的作用是尽量将cluster模块抽象掉,让用户像使用单进程一样,部署多进程Node应用。

// app.js
var http = require(&#39;http&#39;);

http.createServer(function(req, res) {
  res.writeHead(200);
  res.end("hello world");
}).listen(8080);

用PM2从命令行启动这段代码

$ pm2 start app.js -i 4

上面代码的i参数告诉PM2,这段代码应该在cluster_mode启动,且新建worker进程的数量是4个。如果i参数的值是0,那么当前机器有几个CPU内核,PM2就会启动几个worker进程。

如果一个worker进程由于某种原因挂掉了,会立刻重启该worker进程。

# 重启所有worker进程
$ pm2 reload all

每个worker进程都有一个id,可以用下面的命令查看单个worker进程的详情。

$ pm2 show <worker id>

关闭worker进程的时候,可以部署下面的代码,让worker进程监听shutdown消息。一旦收到这个消息,进行完毕收尾清理工作再关闭

process.on(&#39;message&#39;, function(msg) {
  if (msg === &#39;shutdown&#39;) {
    close_all_connections();
    delete_logs();
    server.close();
    process.exit(0);
  }
});

更多node相关知识,请访问:nodejs 教程!!

以上是聊聊Nodejs-cluster模組,介紹一下其使用方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除