一般情况下,当更新代码后,必须重启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=0i<cpusi++){

        //分派子进程
        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.lengthreturn;

            //第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服务时),再重启下一个工作进程,直到全部重启完成。

执行效果:

为了更真观的展示“修改代码,重停机重启”效果,我们加一行代码:

先启动,再修改为:

再通过网页触发重启:

后台输出同样验证了修改后的代码已生效: