取消不丢失数据

时间:2016-03-01 01:27:29

标签: node.js stream

我试图使用node.js转换流来组合一堆不同的数据源(基本上是gzip压缩的csvs,但结构很奇怪,它们都有相同的字节长度)并将组合数据写成MongoDB文件而不用将任何文件完全加载到内存中。一张图片讲述了千言万语。它看起来像这样:

file1       file2      file3      file4     file5      file6 ...
   \          |          |          |         |          /
    --(transform steps: gunzip, remove newlines, etc.)---
     \        |          |          |         |        /
doc: {data1, data2, data3, data4, data5, data6, metadata} <------ combine step
                              ||
                           (MongoDB)

每个可读流(file1,2等)通过管道传输到自己的gunzip和其他一些变换的串行管道中。然后将每个文件流传送到组合器的一个实例。就在它之前,我将一个streamIndex添加到块中,以便我可以在组合器变换中区分它们。像这样:

let slice = chunk.slice(i, i + length);
slice.streamIndex = this.streamIndex;
this.push(slice);

我在组合步骤中需要来自每个流的一个数据,所以当接收到数据时,我会查看我收到的块的streamIndex并缓冲数据,直到每个源都有足够的数据。然后,我将源组合到一个文档中,添加元数据,并通过批量插入将其发送到MongoDB。

问题是流以略微不同的速率读取,如果必须开始缓冲过多的数据,则节点会锁定。如果不加以控制,其中一个流可能很容易遇到比另一个更缓冲的1,000,000多个条目,这会导致巨大的垃圾收集,从而导致节点进程停止运行。

当我知道他们通过以下方式提供了太多数据时,我试图向个别上游添加背压以减慢它们的速度:

  • 从转换/可写函数返回false(在调试器中单步执行似乎表明这根本没有任何影响,并且组合器是可写流还是转换没有起作用)
  • 通过例如corking过度输送流file1.cork()
  • 通过this._writableState.corked = true
  • 手动将合并步骤的可写流设置为corked
  • 最可靠的 - 通过暂时删除违规流来表现:

    this.streams.forEach((stream, i) => {
        if (this.dataBuffers[i].length > MAX_BUFFER_LENGTH) {
            stream.unpipe(this);
        };
    });
    

最后一步(当缓冲区变低时重新进行管道处理)使所有缓冲区平稳地保持在MAX_BUFFER_LENGTH。只有我得到一个流&#39;结束&#39;通过阅读数据,事件只有10-15%左右。我观察到一些数据在试验不同的东西时会丢失(流出管道并流入深渊),所以我只能想象在这里发生同样的事情。

这真的是一个非常微不足道的问题,而且我对溪流来说还是一个新手,所以我可能只做一些愚蠢的事情。基本上我的问题是:我如何让每个流提供一些数据,等待其他人做同样的事情,合并,从每个流中读取更多;等等,不会丢失数据(并且不会缓冲太多)?

最终细节:

  • 所有的连接都是管道,从理论上说它应该是开箱即用的背压(&#39;新模式&#39;流 - 流。暂停/恢复赢了工作,我也不希望它:从我所理解的另一种数据开始缺失的情况来看。 我不想对所有内容施加背压,只是提供过多数据的文件流
  • 设置工作,数据库在同时读取一个(甚至两个)文件时最终得到正确的数据 - 它的节点的贪婪模型&#34;采取任何你能得到的! &#34;有多个流似乎让事情在这里竞争。设置很可能不适用于排版模式,我接下来会尝试这样做。我只是把所有东西都运行而没有任何限速,这就是为什么我现在卡住了。
  • 我不能按顺序处理流 - 一次插入数百万个文档,然后通过查找和更新过程反复更新每个文档非常慢。
  • 我正在寻找的结果看起来很像How to interleave streams (with backpressure) 的海报 想要的标题&#34; zipAsArray&#34; 。据我所知,bacon.js不能处理节点流。
  • 这应该是一个独立服务器上的一次性过程,之后我会像往常一样使用mongodb,所以只要它在合理的时间内完成就没关系它咀嚼多少CPU(有了巨大的垃圾收集,它可能永远不会在这一生中完成。)

0 个答案:

没有答案