Почему выборка узла все чаще занимает больше времени при выполнении цикла на 600 повторений по мере удлинения цикла?

#node.js #node-fetch

#node.js #выборка узла

Вопрос:

Я тестировал выборку узла и решил использовать ее в проекте. В этом проекте я многократно извлекаю ресурс, до 600 раз в течение пары минут. Однако, когда я тестировал выборку узла, я обнаружил некоторое странное поведение: когда я зацикливал выборку, на выборку уходило все больше времени. Я доказал это, сгенерировав временные метки (см. Их Здесь ) для i количества итераций. Это мой тестовый код:

 for(let i = 0; i < 600; i  ){
    var start_time = new Date().getTime();
    fetch('http://localhost:3000').then(a=>{
        var time = (new Date().getTime() - start_time)   'ms'
        console.log(time   ' - '   i)
    })
}
 

Есть ли способ обойти это? Я думаю, что это как-то связано с потоковой обработкой, есть ли обходной путь http / https module?

Кроме того, есть ли причина i , по которой номера итераций не в порядке?

Редактировать:

Я понял, что причина, по которой выборка резко ограничивалась postman и вызывала интенсивное ожидание, однако, когда я разместил простое приложение localhost и увеличил количество итераций до 60000, это заняло намного, намного больше времени, чем ожидалось, и сократилось примерно на 30000 итераций. Есть ли причина для этого? Вот конечные журналы:

 15059ms - 15136
15059ms - 15137
15060ms - 15138
15060ms - 15140
15060ms - 15139
15061ms - 15142
15061ms - 15141
15061ms - 15143
15061ms - 15144
15062ms - 15145
15062ms - 15147
15062ms - 15146
15063ms - 15148
15063ms - 15149
15063ms - 15150
15064ms - 15152
15064ms - 15151
15064ms - 15153
15066ms - 15155
15066ms - 15154
15067ms - 15156
15067ms - 15157
15067ms - 15158
15067ms - 15159
15070ms - 15160
15073ms - 15161
15074ms - 15162
15074ms - 15163
15074ms - 15164
15074ms - 15165
15075ms - 15166
15075ms - 15167
15076ms - 15168
15076ms - 15169
15076ms - 15170
15077ms - 15171
15077ms - 15172
15077ms - 15173
15077ms - 15174
15078ms - 15175
15078ms - 15176
15078ms - 15177
15081ms - 15178
15081ms - 15179
15082ms - 15180
15082ms - 15181
15082ms - 15182
15083ms - 15183
15083ms - 15184
15083ms - 15185
15085ms - 15186
15086ms - 15187
15086ms - 15188
15086ms - 15189
15087ms - 34758
 

Есть ли причина, по которой: 1) итерации были значительно ниже ожидаемых и 2) время в мс значительно выше, чем ожидалось? Вот код для отредактированного теста:

 for(let i = 0; i < 60000; i  ){
    var start_time = new Date().getTime();
    get('http://localhost:3000').text().then(a=>{
        var time = (new Date().getTime() - start_time)   'ms'
        console.log(time   ' - '   i)
    })
}
 

Спасибо!

Комментарии:

1. Я бы подумал, что это ограничение скорости на стороне сервера

2. @Dominik ах, большое спасибо! Я протестирую это локально. Спасибо

3. @Dominik можете ли вы ответить на это своим комментарием? Я только что протестировал локально и подтвердил, что то, что вы сказали, было правдой, мой api ограничивал вызовы (честно говоря, я не понимаю, почему я установил для этого значение true). Большое спасибо, это прояснило большую загадку

Ответ №1:

Как упоминалось в комментариях, это, вероятно, связано с ограничением скорости на стороне сервера. Выполнение одного и того же теста локально, скорее всего, даст другой результат.

Редактировать: ваш локальный сервер через некоторое время будет заполнен запросами, и ему придется отрабатывать нагрузку, поэтому со временем она становится все медленнее и медленнее. Здесь вам поможет одно эмпирическое правило: http-запросы стоят дорого, и это первое узкое место, которого вам следует избегать.

Другой способ справиться с этим — добавить балансировщик нагрузки перед вашим сервером, чтобы вы могли масштабировать свой сервер на несколько машин.

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

Комментарии:

1. спасибо за ответ, хотя это правильный ответ, я отредактировал его, задав новый вопрос. Спасибо!

2. Я добавил новый раздел к ответу.

3. Большое спасибо! Извините, что не понял этого раньше.

4. Не извиняйтесь. Мы все многого не знаем 😉 Рад, что смог помочь

Ответ №2:

Это много вопросов в одном, но..

Почему это происходит?

Код выглядит нормально, скорее всего, веб-сайт, на который вы нажимаете, имеет ограничение скорости (вы можете нажимать на него только x раз в минуту, прежде чем он намеренно начнет замедлять ваши запросы, чтобы предотвратить DoS-атаки).

Есть ли обходной путь?

Если ваше замедление связано с ограничением скорости на веб-сайте (попробуйте другой без ограничения скорости, может быть, что-то вроде google.com сработало бы), то нет.

Есть ли причина, по которой номера итераций ( i ) не в порядке?

ДА. Вы отправляете все запросы асинхронно. Порядок, в котором регистрируется ваш вывод, зависит от времени получения ответов. Если они получены не по порядку, ваши i s будут не по порядку.

Ответ на отредактированный вопрос:

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

Возможные узкие места:

  • Медленный ответ сервера. Возможно, серверу (конечной точке вашего HTTP-запроса) требуется много времени для ответа. Вы можете определить время отклика сервера, просмотрев журналы сервера, или попробовать веб-сервис, скорость которого не ограничена. Локальный сервер, например nginx , обслуживающий статические файлы, должен работать достаточно хорошо.
  • Замедление работы ОС. Существует ограничение на максимальное одновременное количество TCP-соединений, которое может обрабатывать операционная система. Поскольку вы открываете все эти соединения более или менее параллельно, ваши 60 тыс. запросов приближаются к максимуму в 65535 открытых соединений. Если вы используете локальный сервер на той же машине, то вы также используете сокет для ответа на каждое TCP-соединение — у вас будет вдвое меньше доступных сокетов от теоретического максимума.
  • libuv Превышение предела пула потоков узла. Асинхронные задачи, которые выполняют ввод-вывод в узле, выполняются из пула потоков. Размер этого пула потоков по умолчанию равен 4, что означает, что только 4 задачи ввода-вывода могут выполняться асинхронно одновременно. Попробуйте увеличить этот предел, установив UV_THREADPOOL_SIZE гораздо большее число (скажем, 100 или 400 ), и посмотрите, получите ли вы пропорциональное увеличение количества запросов, которые могут быть отправлены без замедления, или уменьшение количества замедлений.
  • Сбор мусора в памяти. Ваш код не содержит много переменных, но библиотека, которую вы используете ( get ), может. Если это так, то изменение библиотеки или использование встроенных модулей узла для HTTP-выборки вызовут заметные изменения в замедлении

Комментарии:

1. спасибо за ответ, хотя это правильный ответ, я отредактировал свой пост, задав новый вопрос. Спасибо!

2. @imaginate, возможно, должен был быть новым вопросом, но я все равно ответил