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


288

채팅 웹 응용 프로그램에 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)

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


3
@GottZ 어쩌면 이것이 노드 js에서 일하는 누군가에게 도움이 될 수 있습니다 gist.github.com/samsonradu/1b0c6feb438f5a53e30e . 오늘 socket.error 핸들러를 배포하고 알려 드리겠습니다.
삼손

1
@Gottz socket.error 핸들은 도움이되지 않지만 process.on ( 'uncaughtException')은 오류를 잡습니다. 오류의 console.log는 다음과 같습니다. {[오류 : ECONNRESET 읽기] 코드 : 'ECONNRESET', errno : 'ECONNRESET', syscall : 'read'}
Samson

1
네트워크 문제 일 수 있습니다. 아시다시피 테스트 할 때 모든 예외를 포착하는 것은 불가능합니다. 일부는 프로덕션 서버에 나타납니다. 서버를 강력하게 만들어야합니다. Redis를 스토리지로 사용하여 세션 삭제를 처리 할 수 ​​있습니다. 노드 서버가 다운 된 후에도 세션이 지속됩니다.
user568109

1
왜 세션 삭제와 관련이 있습니까? 그들은 어쨌든 Redis에 의해 처리됩니다.
Samson

3
핸들러가 설정되지 않은 TCP 소켓 수신은 적어도 하나 이상 있습니다. 이제 그 위치를 확인할 차례입니다 : D
Moss

답변:


253

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

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

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

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

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

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

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

편집 (2013-07-22)

위에서 쓴 것처럼 :

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

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

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


'갑자기 닫힘'을 의미 할 필요는 없습니다. 일반적으로 피어가 이미 정상적으로 닫은 연결에 쓰면 발생합니다. RST를 발행하게됩니다.
Lorne의 후작

1
@EJP“갑자기”라고 쓴 이유는 충분했습니다. 오류 (경고 아님)는 피어가 연결을 재설정했음을 나타냅니다. 원격 피어가 기존 연결을 강제로 닫았습니다. 예기치 않은 강제 종료가 갑자기 발생합니다! (이는 일반적으로 원격 시스템의 피어 응용 프로그램이 갑자기 중지되거나 시스템이 재부팅되거나 원격 응용 프로그램이 원격 소켓의 "하드 닫기"를 사용한 경우 발생합니다.이 오류는 "keep-alive"활동으로 인해 연결이 끊어진 경우에도 발생할 수 있습니다. 하나 이상의 작업이 진행되는 동안 오류를 감지하는 중… 이러한 작업 및 후속 작업은 실패합니다.)
e-sushi

2
테스트를 위해 브라우저 (Chrome)에서 거의 100 API 호출을 일괄 전송하면이 오류가 발생합니다. Chrome이 오버로드되어 연결 중 일부를 종료해야한다고 생각합니다 ... @Samson-자체 도메인에서 각 요청을 처리하고 서버를 다시 시작하지 않고 도메인 오류를 잡는 데 어떤 문제가 있습니까?
supershnee

2
@supershnee 데이터, 응용 프로그램 및 node.js 자체가 알 수없는 상태이기 때문에 포착되지 않은 예외 후에는 항상 서버를 다시 시작해야합니다. 예외 후에 계속하면 데이터가 위험 해집니다. 자세한 내용을 보려면 프로세스에 대한 노드 문서 또는 도메인에 대한 노드 문서를 확인하십시오 .
c1moore

39

플래시 정책 파일을 제공하는 데 필요한 간단한 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)

2
코드에 문제가 있습니까? 쓰기 전에 소켓이 쓰기 가능한지 확인해야합니까?
Samson

Doh, 내가 거의 똑같은 것을 게시하기 전에 이미 해결책을 찾았다는 것을 보지 못했습니다.) 귀하의 질문에 관해서는 소켓이 쓰기 가능한지 확인하더라도 나중에 마이크로 초에 쓸 때와 같지 않을 수 있습니다. 여전히 오류가 발생하므로 이것이 "길"입니다.
Joachim Isaksson

좋아, 이것이 안전한 방법이 있습니까? 오류 처리기 내의 socket.close () 같은? 이 오류 후에 CPU로드가 증가하고 있다고 생각하기 때문에 (확실하지 않음)
Samson

2
나는 항상 socket.destroy()오류 처리기를 호출 하여 확인했습니다. 슬프게도 필요한지 여부는 문서를 찾을 수 없지만 오류가 발생하지 않습니다.
Joachim Isaksson

socket.destroy ()는 내 일을 구했습니다. 감사합니다!
Firas Abd Alrahman

27

노드 업그레이드 후 앱에서 오류가 발생하기 시작한 비슷한 문제가있었습니다. 나는 이것이 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을 사용합니다. 뭔가 여전히 오류가 발생합니다. 다시 한 번, 이것이 의도 된 것으로 생각되며 해결책은 코드의 오류를 처리하는 것입니다.


3
고마워, 나는 그것을 스스로 못 박았다! 전체 앱을 불안정하게 만들기 때문에 오류가 uncaughtException으로 전파되지 않도록하는 것이 중요합니다. 예를 들어, 약 10 개의 ECONNRESET 오류를 발견 한 후 서버가 응답하지 않게되었습니다 (단지 중단하고 연결을 처리하지 못했습니다)
Samson

또한 더 이상 오류를 억제하지 않은 노드 버전 변경에 대해 알고 있었지만 각 버전마다 표시되고 해결되는 많은 문제가 최신 버전으로 표시됩니다. V0.10.13을 사용하고 있습니다. btw
Samson

16

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


4
이상하게도이 오래된 질문에 대한 새로운 답변이 나올 것이라는 점이 이상합니다.하지만 감사합니다
Semicolon

13

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

server.timeout = 0;

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


5
이것은 해결책이 아니라 오류가 발생하지 않고 문제를 일으키는 빠른 수정입니다.
Nishant Ghodke

9

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

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

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

훌륭한 통화이지만 maxConnections기본값은 Infinity입니다. 해당 값을 명시 적으로 재정의 한 경우 (사실대로) 경우에만 해당됩니다.
Gajus

7

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

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

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");
}

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

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


6

또한 개발 중에 ECONNRESET 오류가 발생합니다.이를 해결하는 방법은 nodemon을 사용하여 서버를 시작 하지 않고 서버를 시작하여 "node server.js"문제를 해결하는 것입니다.

이상하지만 나를 위해 일했지만 이제는 ECONNRESET 오류가 다시 표시되지 않습니다.


4

나는이 오류도 가지고 있었고 며칠간의 디버깅 및 분석 후에 해결할 수있었습니다.

내 솔루션

나에게 VirtualBox (Docker 용)가 문제였습니다. VM에서 포트 전달을 구성했으며 전달 된 포트에서만 오류가 발생했습니다.

일반적인 결론

다음과 같은 관찰은 내가 투자해야하는 작업 일을 절약 할 수 있습니다.

  • 나에게 문제는 한 포트의 localhost에서 localhost 로의 연결에서만 발생했습니다. ->이 상수 중 하나를 변경하면 문제가 해결됩니다.
  • 나에게 문제는 내 컴퓨터에서만 발생했습니다-> 다른 사람이 시도하도록하십시오.
  • 나를 위해 문제는 잠시 후에 발생했으며 안정적으로 재현 할 수 없었습니다.
  • 노드 또는 표현 (디버그) 도구로 내 문제를 검사 할 수 없습니다. -> 이것에 시간을 낭비하지 마십시오

-> VM, 방화벽 등과 같은 네트워크 (설정)에 문제가 있는지 확인하십시오. 이것이 문제의 원인 일 수 있습니다.


2

다른 네트워크에 연결 하여 문제를 해결했습니다 . 그것은 가능한 문제 중 하나입니다.

위에서 설명한 것처럼 ECONNRESET 은 TCP 대화가 연결 종료를 갑자기 닫았다는 의미입니다.

인터넷 연결로 인해 일부 서버에 연결하지 못할 수 있습니다. 필자의 경우 mLab (MongoDB 데이터베이스를 호스팅하는 클라우드 데이터베이스 서비스)에 연결하려고했습니다. 그리고 내 ISP가 차단하고 있습니다.


이것은 나를 위해 일했습니다. 몇 시간 전에 정상적으로 작동했던 코드가 갑자기 작동을 멈추고 네트워크 변경으로 인해 문제가 발생했습니다.
Aklank Jain

2

이 문제를 다음과 같이 해결했습니다.

  • Wi-Fi / 이더넷 연결을 끄고 켭니다.
  • 나는 입력했습니다 : npm update터미널에 npm을 업데이트하십시오.
  • 세션에서 로그 아웃했다가 다시 로그인을 시도했습니다

그 후 나는 동일한 npm 명령을 시도했지만 좋은 점이 해결되었습니다. 나는 그것이 그렇게 단순한 지 확신하지 못했습니다.

CENTOS 7을 사용하고 있습니다


0

나는 같은 문제가 있었고 Node.js 버전이 문제 인 것으로 보입니다.

이전 버전의 Node.js (10.14.2)를 설치했으며 nvm을 사용하여 모든 것이 정상이었습니다 (여러 버전의 Node.js를 설치하고 한 버전에서 다른 버전으로 빠르게 전환 할 수 있음).

"깨끗한"솔루션은 아니지만 일시적으로 서비스를 제공 할 수 있습니다.


0

나는 적어도 내 유스 케이스에서 이것을 알아 냈습니다.

나는 받고 있었다 ECONNRESET. 내 클라이언트가 설정 된 방식으로 API 호출로 서버를 매우 빠르게 처리하고 있었고 엔드 포인트를 한 번만 수행하면됩니다.

내가 고쳤을 때 오류가 사라졌습니다.


-2

socket.io에 다음 옵션을 추가하십시오.

const options = { transports: ['websocket'], pingTimeout: 3000, pingInterval: 5000 };

나는 이것이 당신을 도울 것입니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.