2015-03-04 2 views
2

Мой сервер nodejs аварийно падает в реальном времени (и всегда на веб-стресс-инструменте с запросом потока 10+). Ниже приведен код, который, по моему мнению, является основной причиной.Авария NodeJS с несколькими запросами

main.js

-------- 
app = express(): 
--------- 
app.get('/image/*', actions.download); 

actions.js

var request = require('request'); 
exports.download = function(req, res){ 
var url = <Amazon s3 URL>; 
req.pipe(request(url)).pipe(res); 
}; 

Когда сервер выходит из строя, я получаю ниже ошибки в поЬир

stream.js:94 
throw er; // Unhandled stream error in pipe. 
^ 
Error: socket hang up 
at createHangUpError (http.js:1476:15) 
at Socket.socketOnEnd [as onend] (http.js:1572:23) 
at Socket.g (events.js:180:16) 
at Socket.emit (events.js:117:20) 
at _stream_readable.js:943:16 
at process._tickCallback (node.js:419:13) 

Подробный журнал, когда я попытался с sudo NODE_DEBUG=net node main.js и подвергал стресс-тест с 10 нитями

NET: 3017 Socket._read readStart 
NET: 3017 afterWrite 0 { domain: null, bytes: 335, oncomplete: [Function: afterWrite] } 
NET: 3017 afterWrite call cb 
NET: 3017 onread ECANCELED 164640 4092 168732 
NET: 2983 got data 
NET: 2983 onSocketFinish 
NET: 2983 oSF: not ended, call shutdown() 
NET: 2983 destroy undefined 
NET: 2983 destroy 
NET: 2983 close 
NET: 2983 close handle 
Error: read ECONNRESET 
    at errnoException (net.js:904:11) 
    at TCP.onread (net.js:558:19) 
+0

Сколько запросов на секунду? –

+0

Запросы берут около 100 ~ 300 мс. Я получил эту работу безупречно, изменив 'req.pipe (request (url)). Pipe (res)' to 'request (url) .pipe (res)' Начальная реализация была основана на [request] (https://github.com/request/request). Он работает для нормальных условий, но сбой сервера, когда есть пул одновременных запросов. Хотите знать, правильно ли исправление, даже если проблема решена! – sujithkrishnan

ответ

0

Это обсаженный libuv в src/unix/stream.c. Здесь мы имеем:

if (stream->shutdown_req) { 
    /* The UV_ECANCELED error code is a lie, the shutdown(2) syscall is a 
    * fait accompli at this point. Maybe we should revisit this in v0.11. 
    * A possible reason for leaving it unchanged is that it informs the 
    * callee that the handle has been destroyed. 
    */ 
    uv__req_unregister(stream->loop, stream->shutdown_req); 
    uv__set_artificial_error(stream->loop, UV_ECANCELED); 
    stream->shutdown_req->cb(stream->shutdown_req, -1); 
    stream->shutdown_req = NULL; 
} 

Я нашел причину этой проблемы:

  1. stream->shutdown_req был назначен int uv_shutdown(. Так кто-то позвонил uv_shutdown. Кто звонил uv_shutdown?
  2. uv_shutdown - не простая функция. См. here. Имя этой функции: StreamWrap::Shutdown.
  3. StreamWrap::Shutdown Используется в nodejs: SET_INSTANCE_METHOD("shutdown", StreamWrap::Shutdown, 0). shutdown метод входит в состав wrappers/pipe_wrap и wrappers/tcp_wrap
  4. Так кто-то назвал shutdown от nodejs/lib. Это может быть lib/net и lib/tls.
  5. So shutdown вызывается от function onCryptoStreamFinish или function onSocketFinish.

Поэтому вам нужно найти, кто отправил запрос на завершение работы в вашем случае. onread ECANCELED означает, что поток (например, socket1.pipe (socket2)) был убит.

BTW Я думаю, что вы можете обойти проблему, используя специальную технику, чтобы уничтожить трубопроводные гнезда из lib/tls:

pair.encrypted.on('close', function() { 
    process.nextTick(function() { 
    // Encrypted should be unpiped from socket to prevent possible 
    // write after destroy. 
    pair.encrypted.unpipe(socket); 
    socket.destroy(); 
    }); 
}); 
Смежные вопросы