考虑背压,将数据从Cassandra传输到文件

时间:2017-03-03 02:30:32

标签: node.js cassandra stream node-streams

我有Node App收集投票提交并将其存储在Cassandra中。投票存储为base64编码的加密字符串。 API有一个名为/export的端点,它应该获得所有这些投票字符串(可能> 1百万),将它们转换为二进制文件并在votes.egd文件中依次附加它们。然后应该压缩该文件并将其发送给客户端。我的想法是从Cassandra流式传输行,将每个投票字符串转换为二进制并写入WriteStream。 我想将此功能包装在Promise中以便于使用。我有以下内容:

streamVotesToFile(query, validVotesFileBasename) {
  return new Promise((resolve, reject) => {
    const writeStream = fs.createWriteStream(`${validVotesFileBasename}.egd`);

    writeStream.on('error', (err) => {
      logger.error(`Writestream ${validVotesFileBasename}.egd error`);
      reject(err);
    });

    writeStream.on('drain', () => {
      logger.info(`Writestream ${validVotesFileBasename}.egd error`);
    })

    db.client.stream(query)
    .on('readable', function() {
      let row = this.read();
      while (row) {
        const envelope = new Buffer(row.vote, 'base64');
        if(!writeStream.write(envelope + '\n')) {
          logger.error(`Couldn't write vote`);
        }
        row = this.read()
      }
    })
    .on('end', () => { // No more rows from Cassandra
      writeStream.end();
      writeStream.on('finish', () => {
        logger.info(`Stream done writing`);
        resolve();
      });
    })
    .on('error', (err) => { // err is a response error from Cassandra
      reject(err);
    });
  });
}

当我运行它时,它将所有投票附加到文件并下载正常。但是我有一堆问题/问题:

  1. 如果我向/export端点发出请求并运行此函数,则在运行时,对应用程序的所有其他请求都非常慢,或者只是在导出请求完成之前没有完成。我猜是因为事件循环被来自Cassandra流的所有这些事件(每秒数千)所困扰?

  2. 所有投票似乎都写得很好,但我几乎每false次调用都得到writeStream.write()并看到相应的记录消息(见代码)?

  3. 我知道我需要考虑背压和WritableStream的'drain'事件,所以理想情况下我会使用pipe()并将投票管道传输到文件,因为它内置了背压支持(对吗? )但是因为我需要处理每一行(转换为二进制并且可能在将来从其他行字段中添加其他数据),我将如何使用管道?

1 个答案:

答案 0 :(得分:0)

这是TransformStream的完美用例:

const myTransform = new Transform({
  readableObjectMode: true,
  transform(row, encoding, callback) {
    // Transform the row into something else
    const item = new Buffer(row['vote'], 'base64');
    callback(null, item);
  }
});

client.stream(query, params, { prepare: true })
  .pipe(myTransform)
  .pipe(fileStream);

查看有关如何在Node.js API Docs中实施TransformStream的更多信息。