在Node.js中,集群无法正常工作。只有一个工作进程在响应。

5

我正在使用node.js进行聚类练习,我的CPU有两个核心。我创建了两个工作进程,每个工作进程运行一个简单的http服务器。服务器响应回调将会阻塞5秒钟,以便将下一个请求发送给另一个工作进程。为了验证工作进程是否并行工作,我在Firefox中打开了多个选项卡并刷新了每一个,问题是总是(99%)只有一个工作进程响应通过刷新选项卡发出的请求。只有一个工作进程提供一个请求,所有其他请求都被阻塞,直到该工作进程完成。这是我的代码 CODE:

var cluster = require('cluster');
var http = require('http');



if (cluster.isMaster) {
    var cpus = require('os').cpus().length;
    console.log('No of cpus:' + cpus);
    console.log(require('os').cpus());

    for (var i = 0; i < cpus; i++) {
        cluster.fork();
    }

    cluster.on('fork', function(worker) {
        console.log('worker:' + worker.id + " is forked");
    });
    cluster.on('online', function(worker) {
        console.log('worker:' + worker.id + " is online");
    });
    cluster.on('listening', function(worker) {
        console.log('worker:' + worker.id + " is listening");
    });
    cluster.on('disconnect', function(worker) {
        console.log('worker:' + worker.id + " is disconnected");
    });
    cluster.on('exit', function(worker) {
        console.log('worker:' + worker.id + " is dead");
    });

} else {
    http.createServer(function(req, res) {

        console.log('worker:' + cluster.worker.id + " going to send response ");
        res.writeHead(200);
        res.end("hello world. worker: " + cluster.worker.id);
        var stop = new Date().getTime();
        while (new Date().getTime() < stop + 5000) {;
        }
    }).listen(8000);
}

输出:

20 Aug 00:36:11 - [nodemon] restarting due to changes...
20 Aug 00:36:12 - [nodemon] starting `node cluster.js`
No of cpus:2
[ { model: 'Intel(R) Core(TM)2 Duo CPU     E4500  @ 2.20GHz',
    speed: 2200,
    times: { user: 2264671, nice: 0, sys: 698343, idle: 5965109, irq: 98812 } },
  { model: 'Intel(R) Core(TM)2 Duo CPU     E4500  @ 2.20GHz',
    speed: 2200,
    times: { user: 2466000, nice: 0, sys: 502562, idle: 5959203, irq: 4609 } } ]
worker:1 is forked
worker:2 is forked
worker:2 is online
worker:1 is online
worker:2 is listening
worker:1 is listening
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response

我注意到一件事情。如果我强制刷新(ctrl+f5)标签,那么两个工作线程就会依次响应。 输出结果:

我注意到一件事情。如果我强制刷新(ctrl+f5)标签,那么两个工作线程就会依次响应。

worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response

我有点困惑在普通刷新(F5)和强制刷新(Ctrl + F5)时发生了什么。帮助我理清楚这个问题...!


这一切看起来都很好。如果worker1可以处理流量,为什么要麻烦worker2呢?如果worker2从未登录过,那将是一个问题,但我经常在虚假/测试流量负载中看到这种模式。 - dandavis
是的,这是一种虚假/流量负载。我正在尝试集群框架。问题在于只有一个工作进程可以处理一个请求,而所有其他请求都会被阻塞,直到该工作进程完成。 - cJ_
我告诉你这不是问题。集群不是轮流进行,而是根据需求和剩余量来进行,并且主要由操作系统确定。可以将其类比为Northstar引擎,在城市中行驶时关闭不需要的活塞。 - dandavis
感谢您的评论。我的问题是,如果有10个请求到达,每个请求需要5秒钟来处理。那么使用两个工作人员响应将需要25秒钟来处理所有请求,而使用一个工作人员响应将需要50秒钟来处理所有请求。我的问题是,即使我创建了两个工作人员,只有一个工作人员在工作,因此需要50秒来处理所有请求。我正在努力弄清楚为什么第二个工作人员没有工作。 - cJ_
实际上,在这两种情况下,它们都应该在约5秒钟内返回...只是因为你在while循环中消耗了CPU资源,所以你的问题才成为了一个问题。在真正的代码中,这种情况不会发生。 - dandavis
大约晚了2年,但是只有在达到一定的阈值之后,集群才会开始工作。对于我来说,这个阈值大约是1.5GB的内存使用量:https://camo.githubusercontent.com/d04c1918bdeacc72f2b79504aa7eaf1e909920bb/68747470733a2f2f692e6779617a6f2e636f6d2f62316565396361656163373132633365316261306638343331366366383461642e706e67 - NiCk Newman
2个回答

7

表面上看,节点集群似乎并不能实现它所说的功能(至少对我来说是这样)。当我在浏览器中同步生成工作进程时,发现相同的工作进程总是被分配一个请求,而我和你处于相同的情况。我的一位同事用 fiddler 重放了约20个请求。当所有这些请求快速地到达服务器时,比集群管理器可以将它们传递给工作者的速度更快(我猜),那么你会看到有其他工作进程被调用以处理请求。

似乎一旦管理员将请求交给工作者,它就不关心工作者是否阻塞。 它只知道管道中只有一个请求,而且除了第一个工作者之外,没有必要将该请求分配给任何其他人,因为据管理员所知,他可用。


最重要的是并发发送请求,例如使用 ab 工具。谢谢。 - Kirill Oficerov

2

你在响应代码中使用的 while 循环可能会导致一些严重问题。如果你想模拟长时间运行的请求,应该在那里使用 setTimeout

请尝试使用以下代码替换你的 worker:

http.createServer(function(req, res) {
    console.log('worker:' + cluster.worker.id + " going to send response ");
    setTimeout(function() {
       res.writeHead(200);
       res.end("hello world. worker: " + cluster.worker.id);
    }, 5000);
}).listen(8000);

话虽如此,@dandavis在评论中所说的是真的:cluster 不会做轮询负载均衡,因此只要Worker 1 可用于请求,它就会处理这些请求。使用我建议的 setTimeout 实际上会使您的工作进程更多地可用于处理请求,因此如果只是从浏览器手动访问服务器,则很可能只会看到 Worker 1 处理请求。您可能需要一些类型的负载测试脚本才能看到两个工作进程处理请求。

至于您在 F5CTRL-F5 之间看到的差异,我最好的猜测是您的浏览器保持与服务器的连接,因此当您只使用 F5 时,它使用相同的连接,这将始终转到相同的工作进程。当您使用 CTRL-F5 时,它实际上正在关闭它之前拥有的连接,因此可以在下一个请求中连接到任何一个工作进程。


嗨,Mike。我正在学习Node课程,遇到了一个类似的例子,但它对我也不起作用。我意识到这个例子是人为制造的,但它的目的是阻塞事件循环,从而展示集群中的另一个工作进程将会并行处理另一个请求。使用setTimeout的建议不会阻塞事件循环,因为它将使用线程池,如果我理解正确的话,因此抵消了练习的重点。 - Bryan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接