2014-07-12 3 views
2

작은 성능의 노드 데모에서 작업 중이며 setTimeout에 대해 50 회 동시 호출이 500ms가 아닌 4 초 이상 걸린 다음 예제를 보니 놀랍습니다.setTimeout을 동시에 호출하면 예상보다 많은 지연이 발생합니다.

다음 코드는 모든 요청을 수신하고 나중에 setTimeout을 사용하여 500ms 후에 응답하는 매우 간단한 익스프레스 서버를 설정합니다. 그런 다음 요청을 응답하고 해당 응답을 추적하기 위해 50 개의 요청을 번호로 전달하는 클라이언트가 있습니다.

// SERVER 
var express = require('express'); 
var app = express(); 

app.get('*', function (req, res) { 
    setTimeout(function() { 
     return res.send(req.query.i); 
    }, 500); 
}); 

app.listen(8099); 

// CLIENT 
var http = require('http'); 

function start() { 
    for (var i = 0; i < 50; i++) { 
     console.log(new Date().getSeconds() + ':' + new Date().getMilliseconds() + ' - Sending ' + i); 
     http.get('http://localhost:8099?i=' + i, responseHandler); 
    } 

    function responseHandler(res) { 
     res.on('data', function (body) { 
      return console.log(new Date().getSeconds() + ':' + new Date().getMilliseconds() + ' - Received ' + body); 
     }); 
    } 
} 

start(); 

나는 그들 모두가 같은시기에 응답 할 것이다 다음 모든 setTimeout 통화 및은 500ms 이상을 만들 수 30-50ms를 취하도록 코드를 예상했다. 대신 나는 5의 그룹으로 응답한다. 각 그룹 사이에 500ms로 응답한다.

나는 모든 문제를 해결할 수있는 더 간단한 대안을 시도했다. setTimeout을 꺼내 즉시 응답하면 50 개의 응답이 모두 100ms 내에 들어옵니다. 방정식에서 웹 서버를 가져 와서 setTimeout으로 50 건의 호출을하면 모든 50 건의 호출이 즉시 대기하고 50 초 후에 모두 50 건이 동시에 다시 발생합니다.

express 및 http 호출을 setTimeout과 결합 할 때 추가 지연이 발생할 수있는 원인은 무엇입니까?

+0

[이벤트 대기열로 인해] 지연이 발생했습니다 (http://stackoverflow.com/questions/19822668/what-exactly-is-a-node-js-event-loop-tick). –

+0

이 결과를 확인할 수 있습니다. Alex, 그건 도움이되지 않는 코멘트입니다 : * 모든것 * 비동기는 이벤트 큐와 관련이 있습니다. 이것이 "이벤트 대기열로 인해"라고 말하는 것은 "프로그래밍 때문입니다"라고 말하는 것과 같습니다. 무의미한. 내 의심은 노드의 타이머 기능에 "메타 대기열"이 있다는 것입니다.즉, 타이머 대기열에서 Node는 다음 5 개의 사용 가능한 타이머를 사용하여 처리 할 타이머를 예약합니다. 확실하지는 않지만 노드 소스 코드를 살펴보십시오. –

+1

나는 내가 말한 것을 되돌려 놓는다. 나는'setTimeout'의 한계라고 생각하지 않는다. 왜냐하면 Samuel이 그의 글에서 말했듯이, HTTP 요청없이이 테스트를 실행하면 예상대로 작동하기 때문이다. 따라서 HTTP/Express 대기열 문제 여야합니다. –

답변

1

문제는 setTimeout과 아무런 관련이 없습니다 (클라이언트/서버 설정없이 테스트를했을 때 추측했을 수 있습니다). 문제는 노드 http 서버가 주어진 시간에 처리 할 수있는 열린 HTTP 소켓의 수입니다.

이 설정을 제어하는 ​​설정은 Agent.maxSockets입니다 (자세한 내용은 documentation 참조).

maxSockets의 기본값은 5입니다. 따라서 앱에 50 개의 요청을 보내면 번 중 5 번을 처리하여 새로운 요청으로 이동하기 전에 번까지 완료합니다. setTimeout 함수가 콜백을 호출 할 때까지는 완료 할 수 없으므로 약 500 밀리 초마다 5 개의 버스트로 응답합니다.

http.globalAgent.maxSockets = 10; 

지금 당신이 요청하는 대신 10의 버스트 처리 얻을 볼 수 있습니다 : 당신이 증거를 원하는 경우에

, 당신이해야 할 maxSockets의 값을 변경합니다. 50으로 설정하면 찾고자하는 동작을 볼 수 있습니다.

꽤 좋은 이유 때문에 아마도 5로 설정되어 있으므로 문제에 대한 "해결책"은 maxSockets에서 Infinity 또는 그와 같은 무언가로 설정했다고 생각하지 않습니다.

mscdex는 설명에서 cusotm 에이전트를 http.request에 지정할 수 있으며 노드 v0.12에서 기본값 maxSockets이 변경 될 것이라고 지적합니다.

+0

몇 가지주의 사항 : 기본/글로벌 에이전트의 maxSockets를 변경하는 대신'httpServlet()'에 전달할 수있는 자신의'maxSockets'를 가진 새로운/사용자 정의 에이전트 인스턴스를 만들 수 있다는 것을 분명히해야합니다. '. 또한 기본/글로벌 에이전트 인'maxSockets'는 노드 v0.12에서 더 이상 5로 제한되지 않을 것입니다. – mscdex

+0

정보를 제공해 주셔서 감사합니다. mscdex. 내 대답을 업데이트 할게. –

+0

완벽. 그것은 그것을 고쳤다. 내 테스트에서는 50으로 설정했다. 최대 소켓이 필요하지만 5는 매우 적다. 특히 많은 I/O 또는 외부 프로세스에서 대부분의 시간을 기다리는 I/O 집약적 인 애플리케이션을 사용하는 경우에는 더욱 그렇다. –

관련 문제