zoukankan      html  css  js  c++  java
  • [Node.js] Availability and Zero-downtime Restarts

    It might be possible for our node server has some downtime, no matter it is because server update or simply some crashs in the code. We want to minizie the downtime as much as possible.

    1. In case of cluster worker crash, we want master worker fork a new worker:

    const http = require('http');
    const cluster = require('cluster');
    const os = require('os');
    
    if (cluster.isMaster) {
        const cpus = os.cpus().length;
    
        console.log(`Forking for ${cpus} CPUs`);
        for (let i = 0; i < cpus; i++) {
            cluster.fork();
        }
    
        cluster.on('exit', (worker, code, signal) => {
            if (code !== 0 && !worker.exitedAfterDisconnect) {
                console.log(`Worker ${worker.id} crashed. Starting a new wroker`);
                cluster.fork();
            }
        })
    } else {
        require('./server');
    }

    It is important to check 'worker.exitedAfterDisconnect' to see whether is is because crash or because we want to exit one worker.

    2. In case of upgrade, we want to restart each worker one by one, to make zero downtime:

        // kill -SIGUSR2 <MASTER_PID>
        // In case to upgrade, we want to restart each worker one by one
        process.on('SIGUSR2', () => {
            const workers = Object.values(cluster.workers);
            const restartWorker = (workerIndex) => {
                const worker = cluster.workers[workerIndex];
                if (!worker) return;
    
                // On worker exit, we want to restart it, then continue 
                // with next worker
                worker.on('exit', () => {
                    // If it is because crash, we don't continue
                    if (!worker.exitedAfterDisconnect) return;
                    console.log(`Exited process ${worker.process.pid}`);
                    cluster.fork().on('listening', () => {
                        restartWorker(workerIndex + 1);
                    });
    
                    worker.disconnect();
                });
            }
            // Calling restartWorker recursively
            restartWorker(0);
        });

    In really production, we don't actually need to code cluster by ourselve, we can use PM2 package. but it is important to understand what's happening under hood.

    ---

    const cluster = require('cluster');
    const http = require('http');
    const os = require('os');
    
    // For runing for the first time,
    // Master worker will get started
    // Then we can fork our new workers
    if (cluster.isMaster) {
        const cpus = os.cpus().length;
    
        console.log(`Forking for ${cpus} CPUs`);
        for (let i = 0; i < cpus; i++) {
            cluster.fork();
        }
    
        // In case of crash, we want to strat a new worker
        cluster.on('exit', (worker, code, signal) => {
            if (code !== 0 && !worker.exitedAfterDisconnect) {
                console.log(`Worker ${worker.id} crashed. Starting a new wroker`);
                cluster.fork();
            }
        })
    
        // kill -SIGUSR2 <MASTER_PID>
        // In case to upgrade, we want to restart each worker one by one
        process.on('SIGUSR2', () => {
            const workers = Object.values(cluster.workers);
            const restartWorker = (workerIndex) => {
                const worker = cluster.workers[workerIndex];
                if (!worker) return;
    
                // On worker exit, we want to restart it, then continue 
                // with next worker
                worker.on('exit', () => {
                    // If it is because crash, we don't continue
                    if (!worker.exitedAfterDisconnect) return;
                    console.log(`Exited process ${worker.process.pid}`);
                    cluster.fork().on('listening', () => {
                        restartWorker(workerIndex + 1);
                    });
    
                    worker.disconnect();
                });
            }
            // Calling restartWorker recursively
            restartWorker(0);
        });
    } else {
        require('./server');
    }
  • 相关阅读:
    艾伟_转载:基于.NET平台的Windows编程实战(三)—— 项目的创建及主界面的设计 狼人:
    艾伟_转载:C# Design Patterns (2) Strategy 狼人:
    艾伟_转载:C# Design Patterns (5) Prototype 狼人:
    艾伟_转载:正则表达式30分钟入门教程 狼人:
    艾伟_转载:WCF安全之EndPointIdentity 狼人:
    艾伟_转载:老赵谈IL(3):IL可以看到的东西,其实大都也可以用C#来发现 狼人:
    艾伟_转载:.NET平台上的Memcached客户端介绍 狼人:
    艾伟_转载:关于.NET中的循环引用 狼人:
    艾伟_转载:VS 2008快捷键 狼人:
    艾伟_转载:Regex.Replace 方法的性能! 狼人:
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10502056.html
Copyright © 2011-2022 走看看