2013-06-28 2 views
3

Я создал сценарий node.js, который сканирует сеть для доступных HTTP-страниц, поэтому есть много соединений, которые я хочу запускать параллельно, но кажется, что некоторые из запросы ждут, пока предыдущий не завершится.Множество параллельных HTTP-запросов в node.js

Ниже приводится фрагмент кода:

var reply = { }; 
    reply.started = new Date().getTime(); 
    var req = http.request(options, function(res) { 
     reply.status = res.statusCode; 
     reply.rawHeaders = res.headers; 
     reply.headers = JSON.stringify(res.headers); 
     reply.body = ''; 
     res.setEncoding('utf8'); 
     res.on('data', function (chunk) { 
      reply.body += chunk; 
     }); 
     res.on('end', function() { 
      reply.finished = new Date().getTime(); 
      reply.time = reply.finished - reply.started; 
      callback(reply); 
     }); 
    }); 
    req.on('error', function(e) { 
     if(e.message == 'socket hang up') { 
      return; 
     } 
     errCallback(e.message); 
    }); 
    req.end(); 

Этот код выполняет только 10-20 запросов в секунду, но мне нужно 500-1k производительность запросов. Каждый запрошенный в очереди запрос выполняется на другом HTTP-сервере.

Я пытался сделать что-то подобное, но это не помогло:

http.globalAgent.maxSockets = 500; 
+2

Похоже, вы делаете HTTP-запросы. Возможно ли получить так много запросов, которые быстро проходят через интернет-соединение? У меня здесь очень быстрое соединение, но мой пинг на ближайший сервер составляет около 52 мс, что, я думаю, означает, что я могу сделать около 20 HTTP-запросов в секунду. –

+0

Я запускаю этот скрипт на машине, и я уверен, что справится с этим множеством запросов. если быть точным: это сервер hetzner 6s. – druidvav

+0

Конечно, но вы читали, что я сказал? Я не думаю, что вы можете * сделать *, что многие запросы по HTTP с единственным подключением к Интернету, независимо от того, насколько мощна ваша машина. Когда вы делаете HTTP-запрос, вам придется ждать ответа с другого конца. Вы можете, конечно, обслуживать больше запросов, чем это, но это потому, что вы будете обслуживать запросы от многих браузеров, каждый со своим собственным интернет-соединением. –

ответ

3

Я нашел решение для меня, это не очень хорошо, но работает:

childProcess = require('child_process') 

Я использую локон:

childProcess.exec('curl --max-time 20 --connect-timeout 10 -iSs "' + options.url + '"', function (error, stdout, stderr) { } 

Это позволяет запускать 800-1000 свертывание процессов одновременно. Конечно, у этого решения есть недели, такие как требование для множества открытых файловых decriptors, но работает.

Я пробовал привязку к вершине-скручиванию, но это было очень медленно.

2

Что-то еще должно происходить с вашим кодом. Узел может удобно обрабатывать запросы 1k + в секунду.

я тестировал со следующим простым кодом:

var http = require('http'); 

var results = []; 
var j=0; 

// Make 1000 parallel requests: 
for (i=0;i<1000;i++) { 
    http.request({ 
     host:'127.0.0.1', 
     path:'/' 
    },function(res){ 
     results.push(res.statusCode); 
     j++; 

     if (j==i) { // last request 
      console.log(JSON.stringify(results)); 
     } 
    }).end(); 
} 

Чтобы чисто проверить, что узел может и не мой дом широкополосного соединение кодовых запросов от локального сервера Nginx. Я также избегаю console.log, пока все запросы не вернутся, потому что он реализован как синхронная функция (чтобы избежать потери сообщений отладки при сбое программы).

Выполнение кода с помощью time я получаю следующие результаты:

real 0m1.093s 
user 0m0.595s 
sys  0m0.154s 

Это 1.093 секунды на 1000 запросов, что делает его очень близко к 1k запросов в секунду.


Простой код выше будет генерировать ошибки операционной системы, если вы пытаетесь сделать много запросов (например, 10000 или более), поскольку узел будет счастливо попытаться открыть все эти розетки в течение цикла (помните: запросы дон 't начинаются до тех пор, пока цикл for не завершится, они создаются только). Вы упомянули, что ваше решение также сталкивается с теми же ошибками. Чтобы этого избежать, вы должны ограничить количество выполненных параллельных запросов.

Самый простой способ ограничить количество параллельных запросов, чтобы использовать один из Limit функций образуют async.js библиотеку:

var http = require('http'); 
var async = require('async'); 

var requests = []; 

// Build a large list of requests: 
for (i=0;i<10000;i++) { 
    requests.push(function(callback){ 
     http.request({ 
      host:'127.0.0.1', 
      path:'/' 
     },function(res){ 
      callback(null,res.statusCode); 
     }).end() 
    }); 
} 

// Make the requests, 100 at a time 
async.parallelLimit(requests, 100,function(err, results){ 
    console.log(JSON.stringify(results)); 
}); 

Запуск этого с time на моей машине, я получаю:

real 0m8.882s 
user 0m4.036s 
sys  0m1.569s 

Так что это запрос 10k примерно за 9 секунд или примерно 1,1 к/с.

Посмотрите функции, доступные с async.js.

+0

Хороший подход, но что это значит «Работа со временем»? – lesimoes

+1

@lesimoes: 'time' - это программа, доступная на большинстве ОС Unix, включая Linux и MacOS. Как правило, для команд типа 'cd' или' ls' или 'grep' или' awk' или 'time' большинство пользователей unix делают предположение, что все уже знают о них, поэтому никаких интродукций не требуется. Для запуска программы с 'time' вы просто набираете' time my_program'. В этом случае вы должны ввести 'time node my_script.js' – slebetman

+0

Ницца! Большое спасибо! – lesimoes

0

Использование Асинхронный библиотека: https://caolan.github.io/async/docs.html#parallel

Есть еще много функций для запуска, которая просто делает то, что вы хотите. Async - ваш друг :)

+1

Пожалуйста, избегайте просто ссылки на внешние ресурсы и попытайтесь дать некоторый контекст вашему ответу. Взгляните на https://stackoverflow.com/questions/how-to-answer – gareththegeek

Смежные вопросы