2013-03-20 3 views
10

Рассмотрим следующий простой Node.js приложения:Node JS - http.request() проблемы с Пулы соединений

var http = require('http'); 
http.createServer(function() { }).listen(8124); // Prevent process shutting down 

var requestNo = 1; 
var maxRequests = 2000; 

function requestTest() { 
    http.request({ host: 'www.google.com', method: 'GET' }, function(res) { 
     console.log('Completed ' + (requestNo++)); 

     if (requestNo <= maxRequests) { 
      requestTest(); 
     } 
    }).end(); 
} 

requestTest(); 

Это делает 2000 HTTP запросы на google.com, один за другим. Проблема заключается в том, что он запрашивает номер 5 и приостанавливается примерно на 3 минуты, затем продолжает обработку запросов 6 - 10, затем останавливается еще на 3 минуты, затем запрашивает 11 - 15, паузы и т. Д. Редактировать:Я попытался сменить www.google.com на localhost, чрезвычайно простое приложение Node.js, на котором запущена моя машина, которая возвращает «Hello world», я все равно получаю 3-минутную паузу.

Теперь я прочитал, я могу увеличить лимит пула соединений:

http.globalAgent.maxSockets = 20; 

Теперь, если я запускаю его, он обрабатывает запросы 1 - 20, затем делает паузу в течение 3 минут, а затем просит 21 - 40, затем делает паузу , и так далее.

Наконец, после небольшого исследования, я узнал, что я мог бы отключить соединение Объединив полностью установив agent: false в параметрах запроса:

http.request({ host: 'www.google.com', method: 'GET', agent: false }, function(res) { 
    ...snip.... 

... и он будет работать на всех 2000 запросов просто отлично.

Мой вопрос: это хорошая идея? Есть ли опасность, что я могу получить слишком много HTTP-соединений? И почему он останавливается на 3 минуты, конечно, если я закончил с соединением, он должен добавить его прямо в бассейн, готовый к следующему запросу, чтобы использовать, так почему он ждет 3 минуты? Простите мое невежество.

Несоблюдение этого, что является лучшей стратегией для приложения Node.js, создающего потенциально большое количество HTTP-запросов без блокировки или сбоя?

Я запускаю версию Node.js 0.10 на Mac OSX 10.8.2.


Edit: Я нашел, если преобразовать приведенный выше код в цикл и попытаться установить кучу соединений в то же время, я начинаю получать ошибки после того, как около 242 соединений. Ошибка:

Error was thrown: connect EMFILE 
(libuv) Failed to create kqueue (24) 

... и код ...

for (var i = 1; i <= 2000; i++) { 
    (function(requestNo) { 
     var request = http.request({ host: 'www.google.com', method: 'GET', agent: false }, function(res) { 
      console.log('Completed ' + requestNo); 
     }); 

     request.on('error', function(e) { 
      console.log(e.name + ' was thrown: ' + e.message); 
     }); 

     request.end(); 
    })(i); 
} 

Я не знаю, если сильно загружен Node.js приложение может когда-либо достичь, что большое количество одновременных соединений.

+1

У вас заканчиваются файловые дескрипторы, которые по OSX ограничены относительно низким 256 по умолчанию. Вы можете увеличить этот номер с помощью 'ulimit -n 2048', что позволило бы выполнить последующий процесс Node из одной и той же оболочки, чтобы одновременно открыть эти 2000 соединений с Google ** **, но это не то, что вы хотите, я думаю , Я не уверен, откуда идут 3 минуты, звучит как дросселирование в пуле соединений (или, возможно, Google задушивает вас?). – robertklep

+0

Благодарим за информацию о дескрипторах файла OSX. Я предполагаю, что это не будет проблемой на реальном сайте, работающем в Linux. Но что касается 3 минут ожидания, я понимаю, что если я нахожу локальное веб-приложение Node.js на своей машине. –

+1

Чтение [this] (http://nodejs.org/api/http.html#http_class_http_agent), интересно, будет ли 3-минутный таймаут тайм-аутом keep-alive для серверов Google (хотя, если я правильно понимаю документы, если вы продолжаете запрашивать, он не должен дожидаться истечения срока действия этих авиалиний до начала нового запроса ...) – robertklep

ответ

18

Вы должны потреблять ответ.

Помните, что в v0.10 мы приземлились streams2. Это означает, что события data не происходят, пока вы не начнете их искать. Таким образом, вы можете делать такие вещи, как это:

http.createServer(function(req, res) { 
    // this does some I/O, async 
    // in 0.8, you'd lose data chunks, or even the 'end' event! 
    lookUpSessionInDb(req, function(er, session) { 
    if (er) { 
     res.statusCode = 500; 
     res.end("oopsie"); 
    } else { 
     // no data lost 
     req.on('data', handleUpload); 
     // end event didn't fire while we were looking it up 
     req.on('end', function() { 
     res.end('ok, got your stuff'); 
     }); 
    } 
    }); 
}); 

Однако оборотная сторона потоков, которые не теряют данные, когда вы не читаете это, то, что они на самом деле не потерять данные, если вы его не читаете! То есть, они начинаются с паузы, и вы должны прочитать их, чтобы получить что-нибудь.

Итак, что происходит в вашем тесте является то, что вы делаете кучу запросов и не потребляя ответы, а затем в конце концов сокет получает убит гуглом, потому что ничего не происходит, и это предполагает, что вы уже умерли ,

Есть некоторые случаи, когда это невозможно потреблять входящее сообщение: то есть, если вы не добавить обработчик в response события в запросах, или там, где вы полностью написать и закончить response сообщений на сервере без когда-либо читал запрос. В этих случаях мы просто выгружаем данные в мусор для вас.

Однако, если вы слушаете событие 'response', это ваша ответственность за обработку объекта. Добавьте в свой первый пример response.resume(), и вы увидите, что процесс проходит через разумный темп.

+2

Сладкий, спасибо за это! Да, «response.resume()» работает. И, как вы говорите, просто используется ответ «response.on» («data», function() {}) ». Кроме того, просто вызов «this.destroy()» в обратном вызове, похоже, тоже работает. –

+0

Я бы также добавил, что это не совсем ясно видно в документации http://nodejs.org/api/http.html#http_http_request_options_callback - но, вероятно, понятно, если это новое поведение, купленное streams2 и 0.10, только что было выпущенный. –

+0

Где находится http.request в этом программном решении? Как выглядит полный код? – TetraDev

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