一般情況下,當更新代碼後,必須重啟Node,才能使更新的代碼功能生效。
重啟當然是會令程序功能暫時中斷的,雖然這個過程非常短,可能只有幾秒。
普通的程序可能不需要但心這個問題,但如果是非常重要的程序,不允許間斷的程序,又該如何?
使用集群(Cluster),用“零停機重啟”方案,可以很簡單的實現這個需求。
實現代碼:
const cluster = require("cluster");
const os = require("os");
//主進程
if(cluster.isMaster){
console.log("master process id :",process.pid);
//cpu數量(幾核)
const cpus = os.cpus().length;
console.log(`Clustering to ${cpus} CPUS`);
for(let i=0; i<cpus>
//分派子進程
cluster.fork();
}
//如果工作進程關閉了,重啟一個
/*
cluster.on("exit",function(worker,code){
if(code != 0 && !worker.suicide){
console.log("worker crashed. Starting a new worker");
cluster.fork();
}
});
*/
//服務器收到這個消息
process.on("SIGINT",function(){
console.log("ctrl+c");
process.exit();
});
var express = require("express")();
express.listen(9000);
express.get("/restart",function(req,res,next){
const workers = Object.keys(cluster.workers);
//重啟函數
function restart_worker(i){
if(i >= workers.length) return;
//第i個工作進程
var worker = cluster.workers[workers[i]];
console.log(`Stoping worker:${worker.process.pid}`);
//中斷工作進程
worker.disconnect();
//工作進程退出時
worker.on("exit",function(){
/*
if(!worker.suicide){
console.log("suicide");
return;
}
*/
//啟動工作進程
const new_worker = cluster.fork();
//當新的工作進程,準備好,並開始監聽新的連接時,迭代重啟下一個工作子進程
new_worker.on("listening",function(){
restart_worker(i+1);
})
});
}
//重啟第一個工作進程
restart_worker(0);
res.end("restart ok");
});
}else{
//子進程執行內容
const http = require("http");
const pid = process.pid;
http.createServer(function(req,res){
console.log(`Handing request from ${pid}`);
res.end(`Hello from ${pid}\\n`);
}).listen(8000,function(){
console.log(`Started ${pid}`);
})
}
代碼解析:
集群主進程用express提供web服務;
集群工作進程用http提供web服務;
當主進程收到指定消息時(代碼中是訪問restart路徑),開始“零停機重啟”操作。
實現重點是:停掉一個工作進程,並重啟一個新的工作進程,當新的工作進程啟動好,並進入監聽狀態時(即:可正常提供Web服務時),再重啟下一個工作進程,直到全部重啟完成。
執行效果:
為了更真觀的展示“修改代碼,重停機重啟”效果,我們加一行代碼:
先啟動,再修改為:
再通過網頁觸發重啟:
後臺輸出同樣驗證了修改後的代碼已生效:
閱讀更多 小咕嚕wing 的文章