NodeJs: медленный запрос - PullRequest
       27

NodeJs: медленный запрос

0 голосов
/ 31 января 2019

Я обнаружил, что реализация сервера tus (https://tus.io) для nodejs (https://github.com/tus/tus-node-server)) действительно медленная по сравнению с реализацией go (https://github.com/tus/tusd).

Здесь выможет найти сравнение между различными реализациями (запущенными локально, на одной машине, с одним и тем же вводом)

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)

go:

 [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

1 Ответ

0 голосов
/ 15 февраля 2019

Я думаю, у вас есть проблема highWaterMark.

Разница между вашими тестами связана с:

Вы можете видеть добавление значения:

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

Вместо этого, предполагая, что ваша сетевая задержка равнанезначительный (потому что вы локальный), вы можете попытаться создать writeStream с большим водяным знаком:

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

Это должно ускорить запись, но будет стоить больше оперативной памяти.

...