Node介紹9-進程

使用node的時候,不得不關注node的兩個缺點。

  1. 如何充分利用多核cpu的計算能力。
  2. 如何保證進程的健壯性和穩定性。

上面的兩個缺點是把node放在服務器的場景中考慮的。

對于第一個問題,雖然node底層c++是可以使用多線程的,但是因為大部分時候使用node是因為希望使用JavaScript,就不討論這一部分。我們知道JavaScript代碼是單線程的,所以這里想利用多核cpu,就不得不討論多進程了。

第二個問題,由于單線程或者多線程的程序,一旦線程的異常沒有處理,將會引起進程的崩潰,導致服務不可用,所以這里主要討論進程的自動重啟的方法。


node多進程

為了充分利用cpu資源,或者僅僅是為了使用node創建另一個進程(子進程會復制父進程的內存空間,所以父進程加載過的模塊子進程就不需要自己重新加載),我們可以使用node的child_process模塊。下圖是node創建多進程的一個示意圖。

多進程架構

當創建多個進程后,還可以進行進程間通信,通過父進程管理子進程,這樣,web服務器的使用場景中,我們不需要創建很多進程,只需要創建和cpu數目相同的進程,就可以使用node的高并發特性,又能充分利用到cpu的多核并行計算特性。

node進程間通信原理

通過上圖我們可以知道node利用libuv庫來使用操作系統的進程間通信功能。

node多進程實例

上面我們知道node多進程架構的基本結構和原理后,來看一個具體的例子。由于node最初是為了做高性能web服務器的,所以我們看一個和網絡相關的例子。

下面通過node實現多個進程監聽一個端口(比如80端口),當有用戶請求服務時,某一個進程可以響應該請求。

Paste_Image.png
  • 創建parent.js
    master進程只負責創建孩子,這樣master進程邏輯簡單,性能好,不容易崩潰。
var cp = require('child_process');
var child1 = cp.fork('child.js');
var child2 = cp.fork('child.js');

// Open up the server object and send the handle.
var server = require('net').createServer();
server.listen(1337, function () {
  child1.send('server', server);
  child2.send('server', server);
  server.close(); //parent不處理請求
});
  • 創建child.js
    work進程接受http請求,處理請求并返回。由于監聽同一個端口,不占用很多文件句柄,操作系統可以允許創建很多個這樣的進程。
// child.js
var http = require('http');

//The callback is a function which is automatically added to the 'request' event.
var server = http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('handled by child, pid is ' + process.pid + '\n');
});

process.on('message', function (m, tcp) {
  if (m === 'server') {
    tcp.on('connection', function (socket) {
      server.emit('connection', socket); //模擬一個http的connection事件
    });
  }
});
  • 測試例子
curl "http://127.0.0.1:1337/"
會返回handled by child, pid is XXXX

上面例子的要點:

  1. 通過child1.send('server', server);傳遞一個server(tcp)用來監聽端口。
  2. 因為不同進程使用的是同一個server,可以監聽同一個端口。注意這個底層的機制是SO_ REUSEADDR
  3. 當請求響應的來到的時候,操作系統決定哪一個進程處理響應。為搶占式。

穩定性

上面的例子已經可以使用多核cpu了,那么來解決第二個問題,如何處理健壯性問題。比如

  • 狀態管理
  • 平滑重啟
  • 配置動態載入

由于寫一個這樣的模塊并不是簡單的任務,或者簡單的謝謝也沒有什么用,我們直接看一個開源例子PM2

下面是pm2的功能列表,可以看到他有cluster mode等十幾項功能。


PM2功能列表
方便的查看cpu和內存使用

當然一些自動重啟等最基本的功能肯定可以勝任。

多臺服務器

上面并沒有提到把工作進程放到不同的機器上,實際上這是有必要的,比如redis需要內存大的機器,數據庫系統需要磁盤好的機器,業務邏輯需要cpu好的機器。對于這個方面,可以考慮網絡通信方式。推薦zmq

總結

可以看到JavaScript也可以利用多核cpu的強大性能,并且提供了方便的進程間通信方法(父子進程間)。多機之間也可以利用現有的網絡通信機制進行通信。多進程管理方面也有一些開源框架提供了支持。總的來說,在web服務器方面的應用是成熟可靠的。

本文引用了
《深入淺出node.js》
http://pm2.keymetrics.io/
http://nodejs.cn/doc/node/child_process.html
http://nodejs.cn/doc/node/cluster.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 又來到了一個老生常談的問題,應用層軟件開發的程序員要不要了解和深入學習操作系統呢? 今天就這個問題開始,來談談操...
    tangsl閱讀 4,173評論 0 23
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,778評論 18 399
  • 對啊,不應該呢。這么矯情的一人竟然沒有總結一下2016。我感覺也是不應該呢。 2016年1月1日,陸續離校開始準備...
    壹生壹SHI閱讀 196評論 0 2
  • 人生的路有很多條有的是一條條境界,有的是一條條雄偉的大道還有的是一條條藝術的道路有唱歌、跳舞、武術、唱戲還有很多很...
    粉紅色的玫瑰閱讀 78評論 2 1