【问题标题】:node.js cluster, redirecting the childs stdout to file breaks datanode.js 集群,将孩子的标准输出重定向到文件中断数据
【发布时间】:2017-04-27 16:18:23
【问题描述】:

任务是:

  1. 集群创建工人
  2. 每个worker逐行加载一些远程数据并输出到自己的process.stdout
  3. 整个集群的输出被重定向到文件

预期结果:所有工作人员的所有行都连接到结果文件

实际结果:在某些机器上结果如预期,在其他机器上结果是交错的。

在 Ubuntu OS 下的 0.10.47 和 0.12.7 节点上测试。在 Ubuntu 16.04.2 下的两台机器上,结果很好。在Ubuntu 14.04.5下是隔行扫描的。

我需要帮助来了解这种情况并在 14.04 修复它。

cluster.js:

var cluster = require("cluster");

cluster.setupMaster({
    exec: "./worker.js"
});

cluster.fork();
cluster.fork();

worker.js:

var cluster = require("cluster");
var fs = require("fs");

var workerId = cluster.worker && cluster.worker.id || 1;
var stream = fs.createReadStream("./data" + workerId + ".log");

stream.on("end", function () {
    process.exit();
});

stream.pipe(process.stdout);

您需要在同一个文件夹中名为 data1.log 和 data2.log 的两个文件来读取数据:

$ wc -l data*
     9260 data1.log
   111636 data2.log
   120896 total

管道总是能产生良好的效果:

$ node cluster.js | wc -l
120896

重定向到文件只在 Ubuntu 16.04 上提供了良好的结果,但在 Ubuntu 14.04 上却没有。甚至在 Ubuntu 14.04 上它每次都会给出不同的结果:

$ node cluster.js >result.log; wc -l result.log
114135      <= MUST BE 120896
$ node cluster.js >result.log; wc -l result.log
110136      <= MUST BE 120896

重定向到文件以进行添加总是会产生良好的结果:

$ rm result.log
$ node cluster.js >>result.log; wc -l result.log
120896

请注意,生成的文件小于原始文件。它的行数更少,字节数更少。所以我认为来自不同工作人员的线路正在相互重写。

【问题讨论】:

    标签: node.js ubuntu redirect cluster-computing stdout


    【解决方案1】:

    一般而言,您应该避免调用process.exit(),因为当您将缓冲数据发送到某处时可能会导致问题。 process.exit() 几乎立即结束该过程。

    在这种特殊情况下,很可能是process.stdout 在进程退出之前没有完全刷新其内部缓冲区(当process.stdout 写入异步时)。

    我的建议是让工作进程自然退出,只需通过process.disconnect() 断开工作进程中的(未使用的)IPC 通道并删除工作进程中的process.exit()。这应该允许process.stdout 在进程退出之前完全排空/刷新。

    【讨论】:

    • 感谢process.exit 的警告,我会考虑的。但我不认为退出缓冲是问题的原因。节点的内部缓冲区大约为 64k。但在这种情况下,我们损失了几十 mb。
    【解决方案2】:

    要解决这个问题,必须在主代码中明确设置管道模式:

    var cluster = require("cluster");
    
    cluster.setupMaster({
        exec: "./worker.js",
    =>    silent: true
    });
    
    for (var i = 0; i &lt; 2; i++) {
            var worker = cluster.fork();
    =>        worker.process.stdout.pipe(process.stdout);
    =>        worker.process.stderr.pipe(process.stderr);
    }
    

    我认为相同代码在不同版本的 ubuntu 上的行为差异的原因在于 linux 内核文件句柄缓冲区实现。

    【讨论】:

    • 使用silent 将通过管道传输到/dev/null,我认为必须使用不同的设置
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多