[node.js] Node.js에서 오류 ECONNRESET을 어떻게 디버깅합니까?

채팅 웹 응용 프로그램에 Socket.io를 사용하여 Express.js 응용 프로그램을 실행 중이며 24 시간 동안 5 번 정도 무작위로 다음 오류가 발생합니다. 노드 프로세스는 영원히 랩핑되고 즉시 다시 시작됩니다.

문제는 Express를 다시 시작하면 내 사용자가 회의실에서 빠져 나오고 아무도 그것을 원하지 않는다는 것입니다.

웹 서버는 HAProxy에 의해 프록시됩니다. 웹 소켓 및 플래시 소켓 전송 만 사용하면 소켓 안정성 문제가 없습니다. 고의로 이것을 재현 할 수 없습니다.

이것은 Node의 오류입니다 v0.10.11.

    events.js:72
            throw er; // Unhandled 'error' event
                  ^
    Error: read ECONNRESET     //alternatively it s a 'write'
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)
    error: Forever detected script exited with code: 8
    error: Forever restarting script for 2 time

편집 (2013-07-22)

socket.io 클라이언트 오류 처리기와 포착되지 않은 예외 처리기가 모두 추가되었습니다. 이 오류가 발생하는 것으로 보입니다.

    process.on('uncaughtException', function (err) {
      console.error(err.stack);
      console.log("Node NOT Exiting...");
    });

따라서 Socket.io 문제가 아니라 다른 서버에 대한 HTTP 요청 또는 MySQL / Redis 연결이라고 생각합니다. 문제는 오류 스택이 내 코드 문제를 식별하는 데 도움이되지 않는다는 것입니다. 다음은 로그 출력입니다.

    Error: read ECONNRESET
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)

이 원인을 어떻게 알 수 있습니까? 오류를 더 잘 극복하려면 어떻게해야합니까?

자, 매우 장황하지는 않지만 Longjohn의 스택 추적은 다음과 같습니다.

    Exception caught: Error ECONNRESET
    { [Error: read ECONNRESET]
      code: 'ECONNRESET',
      errno: 'ECONNRESET',
      syscall: 'read',
      __cached_trace__:
       [ { receiver: [Object],
           fun: [Function: errnoException],
           pos: 22930 },
         { receiver: [Object], fun: [Function: onread], pos: 14545 },
         {},
         { receiver: [Object],
           fun: [Function: fireErrorCallbacks],
           pos: 11672 },
         { receiver: [Object], fun: [Function], pos: 12329 },
         { receiver: [Object], fun: [Function: onread], pos: 14536 } ],
      __previous__:
       { [Error]
         id: 1061835,
         location: 'fireErrorCallbacks (net.js:439)',
         __location__: 'process.nextTick',
         __previous__: null,
         __trace_count__: 1,
         __cached_trace__: [ [Object], [Object], [Object] ] } }

플래시 소켓 정책 파일을 제공합니다.

    net = require("net")
    net.createServer( (socket) =>
      socket.write("<?xml version=\"1.0\"?>\n")
      socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
      socket.write("<cross-domain-policy>\n")
      socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
      socket.write("</cross-domain-policy>\n")
      socket.end()
    ).listen(843)

이것이 원인이 될 수 있습니까?



답변

이미 추측했을 수도 있습니다 : 연결 오류입니다.

“ECONNRESET” 은 TCP 대화의 다른 쪽이 연결 끝을 갑자기 닫았다는 의미입니다. 이것은 아마도 하나 이상의 응용 프로그램 프로토콜 오류 때문일 수 있습니다. API 서버 로그를보고 무언가에 대해 불평하는지 확인할 수 있습니다.

그러나 당신은 또한 문제를 디버깅 잠재적 오류를 확인하는 방법을 찾고 있기 때문에, 당신은에서 살펴 보셔야합니다 소켓이 NodeJS?에서 오류를 끊지 디버깅하는 방법 모두 질문과 관련하여 유래에 게시했습니다.

개발을위한 빠르고 더러운 솔루션 :

longjohn을 사용 하면 비동기 작업이 포함될 긴 스택 추적을 얻습니다.

깨끗하고 올바른 해결책 : 기술적으로, 노드에서 이벤트를 생성 할 때 아무도 듣지 않을 때마다 발생 합니다'error' . 던지지 않도록 청취자를 올려 놓고 직접 처리하십시오. 그렇게하면 자세한 정보로 오류를 기록 할 수 있습니다.

호출 그룹에 대해 하나의 리스너를 갖기 위해 도메인 을 사용 하고 런타임시 다른 오류를 포착 할 수도 있습니다 . http (Server / Client)와 관련된 각 비동기 작업 이 코드의 다른 부분과 비교하여 서로 다른 도메인 컨텍스트에 있는지 확인하십시오 . 도메인은 자동으로 error이벤트를 수신하여 자체 처리기로 전파합니다. 따라서 해당 핸들러 만 듣고 오류 데이터를 얻습니다. 또한 더 많은 정보를 무료로 얻을 수 있습니다.

편집 (2013-07-22)

위에서 쓴 것처럼 :

“ECONNRESET” 은 TCP 대화의 다른 쪽이 연결 끝을 갑자기 닫았다는 의미입니다. 이것은 아마도 하나 이상의 응용 프로그램 프로토콜 오류 때문일 수 있습니다. API 서버 로그를보고 무언가에 대해 불평하는지 확인할 수 있습니다.

또한 가능한 경우 : 임의의 시간에 다른 쪽이 과부하되어 결과적으로 연결이 끊어집니다. 그렇다면 정확히 연결하려는 대상에 따라 다릅니다.

그러나 한 가지 확실한 점은 TCP 연결에 실제로 읽기 오류가있어 예외가 발생한다는 것입니다. 수정 사항에 게시 한 오류 코드를 보면이를 확인할 수 있습니다.


답변

플래시 정책 파일을 제공하는 데 필요한 간단한 tcp 서버로 인해이 문제가 발생했습니다. 이제 핸들러를 사용하여 오류를 잡을 수 있습니다.

# serving the flash policy file
net = require("net")

net.createServer((socket) =>
  //just added
  socket.on("error", (err) =>
    console.log("Caught flash policy server socket error: ")
    console.log(err.stack)
  )

  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)


답변

노드 업그레이드 후 앱에서 오류가 발생하기 시작한 비슷한 문제가있었습니다. 나는 이것이 Node release v0.9.10으로 되돌아 갈 수 있다고 믿는다.

  • net : ECONNRESET을 억제하지 마십시오 (Ben Noordhuis)

이전 버전에서는 클라이언트 중단시 오류가 발생하지 않았습니다. 클라이언트와의 연결이 끊어지면 노드에서 ECONNRESET 오류가 발생합니다. 나는 이것이 노드를위한 기능이라고 생각하기 때문에 (적어도 나를 위해) 수정은 오류를 처리하는 것이 었습니다. net.socket 핸들러에서 처리하지만.

이것을 증명할 수 있습니다 :

간단한 소켓 서버를 만들고 Node v0.9.9 및 v0.9.10을 얻으십시오.

require('net')
    .createServer( function(socket)
    {
           // no nothing
    })
    .listen(21, function()
     {
           console.log('Socket ON')
    })

v0.9.9를 사용하여 시작한 다음이 서버로 FTP를 시도하십시오. Windows에 있고 FTP 클라이언트가 있지만 텔넷 클라이언트가 없기 때문에 FTP와 포트 21 만 사용하고 있습니다.

그런 다음 클라이언트 쪽에서 연결을 끊으십시오. (나는 단지 Ctrl-C를하고있다)

Node v0.9.9를 사용하면 NO ERROR가 표시되고 Node v.0.9.10 이상을 사용하면 ERROR가 표시됩니다.

프로덕션에서는 v.0.10을 사용합니다. 뭔가 여전히 오류가 발생합니다. 다시 한 번, 이것이 의도 된 것으로 생각되며 해결책은 코드의 오류를 처리하는 것입니다.


답변

오늘도 같은 문제가있었습니다. 몇 가지 연구 후 매우 유용한 --abort-on-uncaught-exceptionnode.js 옵션을 발견했습니다 . 훨씬 더 상세하고 유용한 오류 스택 추적을 제공 할뿐만 아니라 응용 프로그램 충돌시 코어 파일을 저장하여 추가 디버그를 허용합니다.


답변

나는 같은 문제에 직면했지만 다음을 배치하여 완화했습니다.

server.timeout = 0;

전에 server.listen. server여기에 HTTP 서버입니다. 기본 제한 시간은 API 설명서에 따라 2 분 입니다.


답변

서버 간 통신이 있고 server.maxConnections매우 낮은 값으로 설정 한 경우에도 가능하지만 드문 경우가 있습니다 .

노드의 핵심 lib net.js에서 호출 clientHandle.close()하면 ECONNRESET 오류가 발생합니다.

if (self.maxConnections && self._connections >= self.maxConnections) {
  clientHandle.close(); // causes ECONNRESET on the other end
  return;
}


답변

예, 정책 파일을 제공하면 충돌이 발생할 수 있습니다.

반복하려면 코드에 지연을 추가하십시오.

net.createServer( function(socket)
{
    for (i=0; i<1000000000; i++) ;
    socket.write("<?xml version=\"1.0\"?>\n");

telnet포트에 연결 하는 데 사용합니다. 지연 시간이 만료되기 전에 텔넷 연결을 끊으면 socket.write에서 오류가 발생할 때 충돌이 발생하지 않습니다.

여기에서 충돌을 피하려면 소켓을 읽거나 쓰기 전에 오류 처리기를 추가하십시오.

net.createServer(function(socket)
{
    for(i=0; i<1000000000; i++);
    socket.on('error', function() { console.log("error"); });
    socket.write("<?xml version=\"1.0\"?>\n");
}

위의 연결 해제를 시도하면 충돌 대신 로그 메시지가 나타납니다.

완료되면 지연을 제거해야합니다.