關於node.js的進程管理

如果是單純的運行一個node進程,那會比較簡單,例如:

 

node ./example.js

但是一般來說,當我們運行一個node進程之後,我們可能希望對這個進程進行更多的管理,例如,當node程序是一個server服務時,我們就有更多的需求。

 

例如:

 

1.服務掛掉的時候自動重啟。

 

2.列出所有服務,包括服務的信息。

 

3.能夠重啟/終止某個服務。

 

4.為服務的運行記錄日志。

 

 

 

1.服務掛掉的時候自動重啟。

 

對於這個需求,我們需要做的是把服務進程當做一個子進程來運行,當子進程不幸掛瞭,父進程將其重啟,例如:

 

復制代碼

var spawn = require('child_process').spawn;

var cp = spawn(process.execPath,['./example.js']);

 

cp.on('exit',function(){

    //restart

});

復制代碼

假設父進程程序名為pro_a,那麼通過父進程啟動一個子程序會是這樣:

 

pro_a ./example.js

傳入子程序名,由父程序執行。

 

 

 

這樣相當於pro_a程序管理子程序的執行:

 

 

 

 

 

2.列出所有服務,包括服務的信息。

 

假設我們執行example.js之後,還有多個程序需要執行,每個程序都使用pro_a程序來啟動:

 

pro_a ./example.js

pro_a ./server.js

pro_a ./other.js

 

 

情況變成這樣:

 

 

 

 

 

 

 

如上圖,多個pro_a進程對應開啟的多個不同子程序的進程。

 

這時候問題來瞭,我們希望知道所有用pro_a啟動的子進程的進程信息,要怎麼做呢?

 

例如:

 

pro_a -l //列出所有子進程信息

 

 

這時候需求就轉變成:新的pro_a進程需要和其他pro_a進程通信,並獲取其他pro_a進程運行的子進程的信息。

 

 

 

對於UNIX的跨進程通信,有幾種方式,由於這裡不同進程在同一個機器中,因此我們這裡采用UNIX domain socket的方式(不用經過網卡),讓在不同pro_a進程間進行通信。

 

使用這種方式,我們需要做的是pro_a進程每次創建子進程的時候,啟用一個server,並監聽對應的sock文件,那麼當心的pro_a進程啟動之後,就可以通過遍歷所有sock文件並對有效sock文件進行連接,從而能夠和不同pro_a進程之間進行消息的通信。

 

 

 

例如:

 

創建子進程的pro_a:

 

復制代碼

var net = require('net');    

//使用UNIX domain socket

var server = net.createServer(function(socket){    

    socket.setEncoding('UTF8');

    socket.on('data',function(){

        //收到消息後,向請求方發送子進程相關信息

        socket.write(JSON.stringify({

            pid:child_process.pid

            //…

        }));

    });

 

});

 

server.listen(socketPath + 'resume_' + Date.now() + '.sock');       

復制代碼

 

 

這樣每個pro_a進程創建子進程之後,都會對應產生一個sock文件:

 

 

 

 

 

 

 

對於新的pro_a進程,第一步是獲取所有sock文件,並進行連接:

 

復制代碼

var getAllSocketFiles = function(){

    var socketFiles;

    try{

        socketFiles = fs.readdirSync(socketPath);

    }

    catch(ex){

        if(ex.code == 'ENOENT'){

            fs.mkdirSync(socketPath);

        }

 

        socketFiles = fs.readdirSync(socketPath);

    }

    return socketFiles;

};

復制代碼

 

 

針對每個sock文件,創建socket進行連接,並發送消息請求:

 

復制代碼

var socket = new net.Socket();

socket.setEncoding('UTF8');

 

socket.connect(this.socketName,function(){

    socket.write(JSON.stringify({

        //請求對應的子進程信息

    }))

});

 

socket.on('data',function(){

    data = JSON.parse(data);

    //獲得對應子進程信息

});

復制代碼

 

 

 

 

 

 

這樣pro_a進程就能從其他pro_進程中獲取到信息。

 

 

 

3.能夠重啟/終止某個服務。

 

由於我們設置瞭子程序在掛掉後會自動重啟,因此我們需要增加一個命令讓程序在需要時能正常關閉,例如:

 

pro_a -s 1140 //強制終止掉進程號為1140的子進程

 

 

此時該pro_a進程需要連接所有其他pro_a進程並獲取他們的子進程信息(就像上面-l那樣),然後篩選出pid未1140的子進程,再次通過socket發送關閉指令,對應的server接收到關閉指令後把其子進程kill掉。

 

 

 

 

 

4.為服務的運行記錄日志。

 

這個隻需要pro_a監聽子進程的事件,並實時寫入log文件就ok瞭。並且我們可以通過命令讓心的pro_a進程能夠查看某個其他pro_a進程中子進程的log,例如:

 

pro_a -L 1130 // 查看1130的子進程的log

 

 

原理和3相似,獲取所有pro_a進程信息,篩選出pid為1130的子進程,socket發送獲取log的指令,對應server把log信息返回。

發佈留言