NodeJS崩溃与多个请求
我的nodejs服务器实时地随机崩溃(并且总是在Web Stress Tool上使用10+线程请求)。 以下是我认为是根本原因的代码。
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); };
当服务器崩溃时,我在nohup中得到错误
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个线程的压力testing时,详细的日志
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)
这是由src / unix / stream.c中的libuv引起的 。 在这里我们有:
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; }
我发现了这个问题的原因:
-
stream->shutdown_req
被int uv_shutdown(
所以有人叫uv_shutdown
,谁叫uv_shutdown
? -
uv_shutdown
不是一个简单的函数。 看到这里 。 这个函数的名字是StreamWrap::Shutdown
。 -
StreamWrap::Shutdown
用于nodejs
:SET_INSTANCE_METHOD("shutdown", StreamWrap::Shutdown, 0)
。shutdown
方法是wrappers/pipe_wrap
和wrappers/tcp_wrap
- 所以有人从
nodejs/lib
调用shutdown
。 它可以是lib/net
和lib/tls
。 - 所以
shutdown
是从function onCryptoStreamFinish
或function onSocketFinish
。
所以你需要find谁在你的情况下发送关机请求。 onread ECANCELED
意味着stream(例如socket1.pipe(socket2))已被终止。
顺便说一句我认为你可以解决你的问题,通过使用特殊的技术来销毁从lib / tlspipe道sockets:
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(); }); });