【问题标题】:NodeJs: slow req.pipeNodeJs:缓慢的 req.pipe
【发布时间】:2019-06-25 03:28:32
【问题描述】:

我发现与 go 实现 (https://github.com/tus/tusd) 相比,nodejs (https://github.com/tus/tus-node-server) 的 tus (https://tus.io) 的服务器实现确实很慢。

在这里您可以找到不同实现之间的比较(本地运行、相同机器、相同输入)

nodejs:

[2019-01-31 16:22:45,578] INFO Uploading 52428800 bytes chunk from offset: 104857600
[2019-01-31 16:22:47,329] INFO Total bytes sent: 157286400 (kb/s: 29930)

去:

 [2019-01-31 16:26:31,894] INFO Uploading 52428800 bytes chunk from offset: 104857600
    [2019-01-31 16:26:32,348] INFO Total bytes sent: 209715200 (kb/s: 115639)

我探索了 tus-node-server 代码库,然后构建了一个非常简化的服务器实现(我试图减少可能的开销)。

这是代码:

const fs = require('fs');
const express = require('express');
const app = express();

let offset = 0;
let len = Math.pow(2,30);

app.post('/files',(req,res) => {
    console.log("post received");
    res.set({
        'Location': 'http://localhost:8888/files/test',
        'Tus-Resumable': '1.0.0',
    });
    res.status(201).end();
});

app.options('/files',(req,res) => {
    console.log("options received");
    res.set({
        'Location': 'http://localhost:8888/files/test',
        'Tus-Resumable': '1.0.0',
        'Tus-Version': '1.0.0,0.2.2,0.2.1'
    });
    res.status(200).end();
});

app.head('/files/test',(req,res) => {
    console.log("options received");
    res.set({
        'Upload-Offset': offset,
        'Upload-Length': len
    });
    res.status(200).end();
});

app.patch('/files/test',(req, res) => {
    let localOffset = parseInt(req.get('Upload-Offset'), 10);
    // the file is pre-created
    const path = `./file.tmp`;
    const options = {
        flags: 'r+',
        start: localOffset
    };

    const stream = fs.createWriteStream(path, options);

    let new_offset = 0;
    req.on('data', (buffer) => {
        new_offset += buffer.length;
    });


    return req.pipe(stream).on('finish', () => {

        localOffset += new_offset;

        offset = localOffset;

        res.set({
            'Upload-Offset': offset,
            'Upload-Length': len
        });
        res.status(204).end();
    });


});

const host = 'localhost';
const port = 8888;
app.listen(port, host, (err, resp) => {
    if(err) {
        console.error(err);
        return
    }
    console.log('listening')
});

我认为性能不佳是由于以下代码块:

const stream = fs.createWriteStream(path, options);
req.pipe(stream)

我还使用管道检查了文件副本,我得到了很好的性能(类似于 go 实现)

const fs = require('fs');
const path = require('path');
const from = path.normalize(process.argv[2]);
const to = path.normalize(process.argv[3]);

const readOpts = {}; // {highWaterMark: Math.pow(2,16)};
const writeOpts ={}; // {highWaterMark: Math.pow(2,16)};

const startTs = Date.now();
const source = fs.createReadStream(from, readOpts);
const dest = fs.createWriteStream(to, writeOpts);
let offset = 0;

source.on('data', (buffer) => {
    offset += buffer.length;
});

dest.on('error', (e) => {
    console.log('[FileStore] write: Error', e);
});

source.pipe(dest).on('finish',() => {
    const endTs = Date.now();
    const kbs = (offset / (endTs - startTs)) / 1000;
    console.log("SPEED: ", kbs, offset);
});

所以瓶颈似乎是处理请求和管道。

能否请您帮我理解发生了什么以及为什么与 go 版本相比如此缓慢

【问题讨论】:

  • 嗨,node.js 的哪个版本?
  • 我试过 v8 和 v10.15.1 结果相同
  • 能否也添加 tus 客户端?我想尝试找出问题????
  • 这里可以找到客户:paste.arn-fai.net/?2866606
  • 如果我使用以下命令行运行 tusd:“tusd -dir ./files -port 1081 -host localhost”我得到类似的性能(如节点)。如果我在“所有接口”上绑定节点,我会获得更好的性能,但我不明白为什么会这样。

标签: node.js performance express stream pipe


【解决方案1】:

我认为您在这里遇到了highWaterMark 问题。

您的测试之间的差异是由于:

你可以看到增值:

console.log('readableHighWaterMark', req.readableHighWaterMark);

相反,假设您的网络延迟可以忽略不计(因为您是本地主机),您 可以尝试创建具有更大水印的writeStream

const options = {
    flags: 'w',
    start: localOffset,
    highWaterMark: 1048576
};
const stream = fs.createWriteStream(path, options);

这应该会加快写入速度,但会消耗更多 RAM。

【讨论】:

  • 点赞!抱歉,如果这是一条不相关的评论,但即使在阅读了文档之后,我仍然无法理解超出 highwatermark 的缓冲区开始推送的某种限制,增加或减少 highwatermark 的值实际上会做什么
  • 举个例子:访问磁盘比访问 RAM 慢很多。如果缓冲区很小,则需要从磁盘读取更多次,因此速度会变慢。增加 HighWaterMark 您将增加内部缓冲区,因此,通过 1 个磁盘访问,您将读取更多数据。从 http 请求中读取是相同的,因为您正在从作为文件描述符的套接字读取.. 末尾的文件
猜你喜欢
  • 2018-07-19
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 2016-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多