zoukankan      html  css  js  c++  java
  • [Node.js] Load balancing a Http server

    Let's see how to do load balancing in Node.js.

    Before we start with the solution, you can do a test to see the ability concurrent requests your current machine can handle.

    This is our server.js:

    const http = require('http');
    const pid = process.pid;
    // listen the mssage event on the global
    // then do the computation
    process.on('message', (msg) => {
        const sum = longComputation();
        process.send(sum);
    })
    
    http.createServer((req, res) => {
        for (let i = 0; i<1e7; i++); // simulate CPU work
        res.end(`Handled by process ${pid}`)
    }).listen(8000, () => {
        console.log(`Started process ${pid}`);
    })

    Test 200 concurrent requests in 10 seconds.

    ab -c200 -t10 http:localhost:8000/

    For one single node server can handle 51 requsts / second:

    Create cluster.js:

    // Cluster.js
    const cluster = require('cluster');
    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();
        }
    } else {
        require('./server'); 
    }

    For the first time Master worker is running, we just need to create as many workers as our cpus allows. Then next run, we just require our server.js; that's it! simple enough!

    Running:

    node cluster.js

    When you refresh the page, you should be able to see, we are assigned to different worker.

    Now, if we do the ab testing again:

    ab -c200 -t10 http:localhost:8000/

    The result is 181 requests/second!


    Sometimes it would be ncessary to communcation between master worker and cluster wokers.

    Cluster.js:

    We can send information from master worker to each cluster worker:

    const cluster = require('cluster');
    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();
        }
    
        console.dir(cluster.workers, {depth: 0});
        Object.values(cluster.workers).forEach(worker => {
            worker.send(`Hello Worker ${worker.id}`);
        })
    } else {
        require('./server'); 
    }

    In the server.js, we can listen to the events:

    const http = require('http');
    const pid = process.pid;
    // listen the mssage event on the global
    // then do the computation
    process.on('message', (msg) => {
        const sum = longComputation();
        process.send(sum);
    })
    
    http.createServer((req, res) => {
        for (let i = 0; i<1e7; i++); // simulate CPU work
        res.end(`Handled by process ${pid}`)
    }).listen(8000, () => {
        console.log(`Started process ${pid}`);
    })
    
    process.on('message', msg => {
        console.log(`Message from master: ${msg}`)
    })

    A one patical example would be count users with DB opreations;

    // CLuster.js
    
    const cluster = require('cluster');
    const os = require('os');
    /**
     * Mock DB Call
     */
    const numberOfUsersDB = function() {
        this.count = this.count || 6;
        this.count = this.count * this.count;
        return this.count;
    }
    
    // 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();
        }
    
        const updateWorkers = () => {
            const usersCount = numberOfUsersDB();
            Object.values(cluster.workers).forEach(worker => {
                worker.send({usersCount});
            });
        }
    
        updateWorkers();
        setInterval(updateWorkers, 10000);
    } else {
        require('./server');
    }

    Here, we let master worker calculate the result, and every 10 seconds we send out the result to all cluster workers.

    Then in the server.js, we just need to listen the request:

    let usersCount;
    http.createServer((req, res) => {
        for (let i = 0; i<1e7; i++); // simulate CPU work
        res.write(`Users ${usersCount}`);
        res.end(`Handled by process ${pid}`)
    }).listen(8000, () => {
        console.log(`Started process ${pid}`);
    })
    
    process.on('message', msg => {
        usersCount = msg.usersCount;
    })
  • 相关阅读:
    thinkpa R61i安装XP SATA的解决方法
    成都港宏4S店买的日产,送的无牌DVD 和可视倒车品牌是路特仕 80007
    设计模式之:解剖观察者模式
    java使用siger 获取服务器硬件信息(CPU 内存 网络 io等)
    lephone 壁纸(裸婚时代 童佳倩姚笛壁纸)
    C# 让程序自动以管理员身份运行
    项目管理的5大过程组、9大知识域、44个管理流程的映射关系
    Spring Security 中如何让用户名不存在的错误显示出来(用户名不存在显示Bad credentials)
    eclipse老是报ThreadPoolExecutor$Worker.run()
    Unison文件夹同步工具
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10498717.html
Copyright © 2011-2022 走看看